1/* 2 * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files or portions 6 * thereof (the "Software"), to deal in the Software without restriction, 7 * including without limitation the rights to use, copy, modify, merge, 8 * publish, distribute, sublicense, and/or sell copies of the Software, 9 * and to permit persons to whom the Software is furnished to do so, subject 10 * to the following conditions: 11 * 12 * * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * * Redistributions in binary form must reproduce the above copyright notice 16 * in the binary, as well as this list of conditions and the following 17 * disclaimer in the documentation and/or other materials provided with 18 * the distribution. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 * THE SOFTWARE. 27 * 28 */ 29 30 31#include <BufferGroup.h> 32 33#include <Buffer.h> 34 35#include "MediaDebug.h" 36#include "DataExchange.h" 37#include "SharedBufferList.h" 38 39 40BBufferGroup::BBufferGroup(size_t size, int32 count, uint32 placement, 41 uint32 lock) 42{ 43 CALLED(); 44 fInitError = _Init(); 45 if (fInitError != B_OK) 46 return; 47 48 // This one is easy. We need to create "count" BBuffers, 49 // each one "size" bytes large. They all go into one 50 // area, with "placement" and "lock" attributes. 51 // The BBuffers created will clone the area, and 52 // then we delete our area. This way BBuffers are 53 // independent from the BBufferGroup 54 55 // don't allow all placement parameter values 56 if (placement != B_ANY_ADDRESS && placement != B_ANY_KERNEL_ADDRESS) { 57 ERROR("BBufferGroup: placement != B_ANY_ADDRESS " 58 "&& placement != B_ANY_KERNEL_ADDRESS (0x%#" B_PRIx32 ")\n", 59 placement); 60 placement = B_ANY_ADDRESS; 61 } 62 63 // first we roundup for a better placement in memory 64 size_t allocSize = (size + 63) & ~63; 65 66 // now we create the area 67 size_t areaSize 68 = ((allocSize * count) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); 69 70 void* startAddress; 71 area_id bufferArea = create_area("some buffers area", &startAddress, 72 placement, areaSize, lock, B_READ_AREA | B_WRITE_AREA | B_CLONEABLE_AREA); 73 if (bufferArea < 0) { 74 ERROR("BBufferGroup: failed to allocate %ld bytes area\n", areaSize); 75 fInitError = (status_t)bufferArea; 76 return; 77 } 78 79 buffer_clone_info info; 80 81 for (int32 i = 0; i < count; i++) { 82 info.area = bufferArea; 83 info.offset = i * allocSize; 84 info.size = size; 85 86 fInitError = AddBuffer(info); 87 if (fInitError != B_OK) 88 break; 89 } 90 91 delete_area(bufferArea); 92} 93 94 95BBufferGroup::BBufferGroup() 96{ 97 CALLED(); 98 fInitError = _Init(); 99 if (fInitError != B_OK) 100 return; 101 102 // this one simply creates an empty BBufferGroup 103} 104 105 106BBufferGroup::BBufferGroup(int32 count, const media_buffer_id* buffers) 107{ 108 CALLED(); 109 fInitError = _Init(); 110 if (fInitError != B_OK) 111 return; 112 113 // This one creates "BBuffer"s from "media_buffer_id"s passed 114 // by the application. 115 116 buffer_clone_info info; 117 118 for (int32 i = 0; i < count; i++) { 119 info.buffer = buffers[i]; 120 121 fInitError = AddBuffer(info); 122 if (fInitError != B_OK) 123 break; 124 } 125} 126 127 128BBufferGroup::~BBufferGroup() 129{ 130 CALLED(); 131 if (fBufferList != NULL) 132 fBufferList->DeleteGroupAndPut(fReclaimSem); 133 134 delete_sem(fReclaimSem); 135} 136 137 138status_t 139BBufferGroup::InitCheck() 140{ 141 CALLED(); 142 return fInitError; 143} 144 145 146status_t 147BBufferGroup::AddBuffer(const buffer_clone_info& info, BBuffer** _buffer) 148{ 149 CALLED(); 150 if (fInitError != B_OK) 151 return B_NO_INIT; 152 153 status_t status = fBufferList->AddBuffer(fReclaimSem, info, _buffer); 154 if (status != B_OK) { 155 ERROR("BBufferGroup: error when adding buffer\n"); 156 return status; 157 } 158 atomic_add(&fBufferCount, 1); 159 return B_OK; 160} 161 162 163BBuffer* 164BBufferGroup::RequestBuffer(size_t size, bigtime_t timeout) 165{ 166 CALLED(); 167 if (fInitError != B_OK) 168 return NULL; 169 170 if (size <= 0) 171 return NULL; 172 173 BBuffer *buffer = NULL; 174 fRequestError = fBufferList->RequestBuffer(fReclaimSem, fBufferCount, 175 size, 0, &buffer, timeout); 176 177 return fRequestError == B_OK ? buffer : NULL; 178} 179 180 181status_t 182BBufferGroup::RequestBuffer(BBuffer* buffer, bigtime_t timeout) 183{ 184 CALLED(); 185 if (fInitError != B_OK) 186 return B_NO_INIT; 187 188 if (buffer == NULL) 189 return B_BAD_VALUE; 190 191 fRequestError = fBufferList->RequestBuffer(fReclaimSem, fBufferCount, 0, 0, 192 &buffer, timeout); 193 194 return fRequestError; 195} 196 197 198status_t 199BBufferGroup::RequestError() 200{ 201 CALLED(); 202 if (fInitError != B_OK) 203 return B_NO_INIT; 204 205 return fRequestError; 206} 207 208 209status_t 210BBufferGroup::CountBuffers(int32* _count) 211{ 212 CALLED(); 213 if (fInitError != B_OK) 214 return B_NO_INIT; 215 216 *_count = fBufferCount; 217 return B_OK; 218} 219 220 221status_t 222BBufferGroup::GetBufferList(int32 bufferCount, BBuffer** _buffers) 223{ 224 CALLED(); 225 if (fInitError != B_OK) 226 return B_NO_INIT; 227 228 if (bufferCount <= 0 || bufferCount > fBufferCount) 229 return B_BAD_VALUE; 230 231 return fBufferList->GetBufferList(fReclaimSem, bufferCount, _buffers); 232} 233 234 235status_t 236BBufferGroup::WaitForBuffers() 237{ 238 CALLED(); 239 if (fInitError != B_OK) 240 return B_NO_INIT; 241 242 // TODO: this function is not really useful anyway, and will 243 // not work exactly as documented, but it is close enough 244 245 if (fBufferCount < 0) 246 return B_BAD_VALUE; 247 if (fBufferCount == 0) 248 return B_OK; 249 250 // We need to wait until at least one buffer belonging to this group is 251 // reclaimed. 252 // This has happened when can aquire "fReclaimSem" 253 254 status_t status; 255 while ((status = acquire_sem(fReclaimSem)) == B_INTERRUPTED) 256 ; 257 if (status != B_OK) 258 return status; 259 260 // we need to release the "fReclaimSem" now, else we would block 261 // requesting of new buffers 262 263 return release_sem(fReclaimSem); 264} 265 266 267status_t 268BBufferGroup::ReclaimAllBuffers() 269{ 270 CALLED(); 271 if (fInitError != B_OK) 272 return B_NO_INIT; 273 274 // because additional BBuffers might get added to this group betweeen 275 // acquire and release 276 int32 count = fBufferCount; 277 278 if (count < 0) 279 return B_BAD_VALUE; 280 if (count == 0) 281 return B_OK; 282 283 // we need to wait until all BBuffers belonging to this group are reclaimed. 284 // this has happened when the "fReclaimSem" can be aquired "fBufferCount" 285 // times 286 287 status_t status = B_ERROR; 288 do { 289 status = acquire_sem_etc(fReclaimSem, count, B_RELATIVE_TIMEOUT, 0); 290 } while (status == B_INTERRUPTED); 291 292 if (status != B_OK) 293 return status; 294 295 // we need to release the "fReclaimSem" now, else we would block 296 // requesting of new buffers 297 298 return release_sem_etc(fReclaimSem, count, 0); 299} 300 301 302// #pragma mark - deprecated BeOS R4 API 303 304 305status_t 306BBufferGroup::AddBuffersTo(BMessage* message, const char* name, bool needLock) 307{ 308 CALLED(); 309 if (fInitError != B_OK) 310 return B_NO_INIT; 311 312 // BeOS R4 legacy API. Implemented as a wrapper around GetBufferList 313 // "needLock" is ignored, GetBufferList will do locking 314 315 if (message == NULL) 316 return B_BAD_VALUE; 317 318 if (name == NULL || strlen(name) == 0) 319 return B_BAD_VALUE; 320 321 BBuffer* buffers[fBufferCount]; 322 status_t status = GetBufferList(fBufferCount, buffers); 323 if (status != B_OK) 324 return status; 325 326 for (int32 i = 0; i < fBufferCount; i++) { 327 status = message->AddInt32(name, int32(buffers[i]->ID())); 328 if (status != B_OK) 329 return status; 330 } 331 332 return B_OK; 333} 334 335 336// #pragma mark - private methods 337 338 339/* not implemented */ 340//BBufferGroup::BBufferGroup(const BBufferGroup &) 341//BBufferGroup & BBufferGroup::operator=(const BBufferGroup &) 342 343 344status_t 345BBufferGroup::_Init() 346{ 347 CALLED(); 348 349 // some defaults in case we drop out early 350 fBufferList = NULL; 351 fRequestError = B_ERROR; 352 fBufferCount = 0; 353 354 // Create the reclaim semaphore 355 // This is also used as a system wide unique identifier for this group 356 fReclaimSem = create_sem(0, "buffer reclaim sem"); 357 if (fReclaimSem < 0) { 358 ERROR("BBufferGroup::InitBufferGroup: couldn't create fReclaimSem\n"); 359 return (status_t)fReclaimSem; 360 } 361 362 fBufferList = BPrivate::SharedBufferList::Get(); 363 if (fBufferList == NULL) { 364 ERROR("BBufferGroup::InitBufferGroup: SharedBufferList::Get() " 365 "failed\n"); 366 return B_ERROR; 367 } 368 369 return B_OK; 370} 371 372