vfs: check userland buffers before reading them.
[haiku.git] / src / kits / media / BufferGroup.cpp
blobe589aa30fb55060216f69ce43b0c36930497248b
1 /*
2 * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
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:
12 * * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
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.
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.
31 #include <BufferGroup.h>
33 #include <Buffer.h>
35 #include "debug.h"
36 #include "DataExchange.h"
37 #include "SharedBufferList.h"
40 BBufferGroup::BBufferGroup(size_t size, int32 count, uint32 placement,
41 uint32 lock)
43 CALLED();
44 fInitError = _Init();
45 if (fInitError != B_OK)
46 return;
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
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;
63 // first we roundup for a better placement in memory
64 size_t allocSize = (size + 63) & ~63;
66 // now we create the area
67 size_t areaSize
68 = ((allocSize * count) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
70 void* startAddress;
71 area_id bufferArea = create_area("some buffers area", &startAddress,
72 placement, areaSize, lock, B_READ_AREA | B_WRITE_AREA);
73 if (bufferArea < 0) {
74 ERROR("BBufferGroup: failed to allocate %ld bytes area\n", areaSize);
75 fInitError = (status_t)bufferArea;
76 return;
79 buffer_clone_info info;
81 for (int32 i = 0; i < count; i++) {
82 info.area = bufferArea;
83 info.offset = i * allocSize;
84 info.size = size;
86 fInitError = AddBuffer(info);
87 if (fInitError != B_OK)
88 break;
91 delete_area(bufferArea);
95 BBufferGroup::BBufferGroup()
97 CALLED();
98 fInitError = _Init();
99 if (fInitError != B_OK)
100 return;
102 // this one simply creates an empty BBufferGroup
106 BBufferGroup::BBufferGroup(int32 count, const media_buffer_id* buffers)
108 CALLED();
109 fInitError = _Init();
110 if (fInitError != B_OK)
111 return;
113 // This one creates "BBuffer"s from "media_buffer_id"s passed
114 // by the application.
116 buffer_clone_info info;
118 for (int32 i = 0; i < count; i++) {
119 info.buffer = buffers[i];
121 fInitError = AddBuffer(info);
122 if (fInitError != B_OK)
123 break;
128 BBufferGroup::~BBufferGroup()
130 CALLED();
131 if (fBufferList != NULL)
132 fBufferList->DeleteGroupAndPut(fReclaimSem);
134 delete_sem(fReclaimSem);
138 status_t
139 BBufferGroup::InitCheck()
141 CALLED();
142 return fInitError;
146 status_t
147 BBufferGroup::AddBuffer(const buffer_clone_info& info, BBuffer** _buffer)
149 CALLED();
150 if (fInitError != B_OK)
151 return B_NO_INIT;
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;
158 atomic_add(&fBufferCount, 1);
159 return B_OK;
163 BBuffer*
164 BBufferGroup::RequestBuffer(size_t size, bigtime_t timeout)
166 CALLED();
167 if (fInitError != B_OK)
168 return NULL;
170 if (size <= 0)
171 return NULL;
173 BBuffer *buffer = NULL;
174 fRequestError = fBufferList->RequestBuffer(fReclaimSem, fBufferCount,
175 size, 0, &buffer, timeout);
177 return fRequestError == B_OK ? buffer : NULL;
181 status_t
182 BBufferGroup::RequestBuffer(BBuffer* buffer, bigtime_t timeout)
184 CALLED();
185 if (fInitError != B_OK)
186 return B_NO_INIT;
188 if (buffer == NULL)
189 return B_BAD_VALUE;
191 fRequestError = fBufferList->RequestBuffer(fReclaimSem, fBufferCount, 0, 0,
192 &buffer, timeout);
194 return fRequestError;
198 status_t
199 BBufferGroup::RequestError()
201 CALLED();
202 if (fInitError != B_OK)
203 return B_NO_INIT;
205 return fRequestError;
209 status_t
210 BBufferGroup::CountBuffers(int32* _count)
212 CALLED();
213 if (fInitError != B_OK)
214 return B_NO_INIT;
216 *_count = fBufferCount;
217 return B_OK;
221 status_t
222 BBufferGroup::GetBufferList(int32 bufferCount, BBuffer** _buffers)
224 CALLED();
225 if (fInitError != B_OK)
226 return B_NO_INIT;
228 if (bufferCount <= 0 || bufferCount > fBufferCount)
229 return B_BAD_VALUE;
231 return fBufferList->GetBufferList(fReclaimSem, bufferCount, _buffers);
235 status_t
236 BBufferGroup::WaitForBuffers()
238 CALLED();
239 if (fInitError != B_OK)
240 return B_NO_INIT;
242 // TODO: this function is not really useful anyway, and will
243 // not work exactly as documented, but it is close enough
245 if (fBufferCount < 0)
246 return B_BAD_VALUE;
247 if (fBufferCount == 0)
248 return B_OK;
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"
254 status_t status;
255 while ((status = acquire_sem(fReclaimSem)) == B_INTERRUPTED)
257 if (status != B_OK)
258 return status;
260 // we need to release the "fReclaimSem" now, else we would block
261 // requesting of new buffers
263 return release_sem(fReclaimSem);
267 status_t
268 BBufferGroup::ReclaimAllBuffers()
270 CALLED();
271 if (fInitError != B_OK)
272 return B_NO_INIT;
274 // because additional BBuffers might get added to this group betweeen
275 // acquire and release
276 int32 count = fBufferCount;
278 if (count < 0)
279 return B_BAD_VALUE;
280 if (count == 0)
281 return B_OK;
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
287 status_t status = B_ERROR;
288 do {
289 status = acquire_sem_etc(fReclaimSem, count, B_RELATIVE_TIMEOUT, 0);
290 } while (status == B_INTERRUPTED);
292 if (status != B_OK)
293 return status;
295 // we need to release the "fReclaimSem" now, else we would block
296 // requesting of new buffers
298 return release_sem_etc(fReclaimSem, count, 0);
302 // #pragma mark - deprecated BeOS R4 API
305 status_t
306 BBufferGroup::AddBuffersTo(BMessage* message, const char* name, bool needLock)
308 CALLED();
309 if (fInitError != B_OK)
310 return B_NO_INIT;
312 // BeOS R4 legacy API. Implemented as a wrapper around GetBufferList
313 // "needLock" is ignored, GetBufferList will do locking
315 if (message == NULL)
316 return B_BAD_VALUE;
318 if (name == NULL || strlen(name) == 0)
319 return B_BAD_VALUE;
321 BBuffer* buffers[fBufferCount];
322 status_t status = GetBufferList(fBufferCount, buffers);
323 if (status != B_OK)
324 return status;
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;
332 return B_OK;
336 // #pragma mark - private methods
339 /* not implemented */
340 //BBufferGroup::BBufferGroup(const BBufferGroup &)
341 //BBufferGroup & BBufferGroup::operator=(const BBufferGroup &)
344 status_t
345 BBufferGroup::_Init()
347 CALLED();
349 // some defaults in case we drop out early
350 fBufferList = NULL;
351 fRequestError = B_ERROR;
352 fBufferCount = 0;
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;
362 fBufferList = BPrivate::SharedBufferList::Get();
363 if (fBufferList == NULL) {
364 ERROR("BBufferGroup::InitBufferGroup: SharedBufferList::Get() "
365 "failed\n");
366 return B_ERROR;
369 return B_OK;