vfs: check userland buffers before reading them.
[haiku.git] / src / servers / media / BufferManager.cpp
blob2db9a551162817032d4ca38c3d26b1d6a08609d2
1 /*
2 * Copyright 2002, Marcus Overhagen. All rights reserved.
3 * Copyright 2009, Axel Dörfler, axeld@pinc-software.de.
4 * Distributed under the terms of the MIT License.
5 */
8 #include "BufferManager.h"
10 #include <Autolock.h>
12 #include "debug.h"
13 #include "SharedBufferList.h"
16 BufferManager::BufferManager()
18 fSharedBufferList(NULL),
19 fSharedBufferListArea(-1),
20 fNextBufferID(1),
21 fLocker("buffer manager locker")
23 fSharedBufferListArea
24 = BPrivate::SharedBufferList::Create(&fSharedBufferList);
28 BufferManager::~BufferManager()
30 fSharedBufferList->Put();
34 area_id
35 BufferManager::SharedBufferListArea()
37 return fSharedBufferListArea;
41 status_t
42 BufferManager::RegisterBuffer(team_id team, media_buffer_id bufferID,
43 size_t* _size, int32* _flags, size_t* _offset, area_id* _area)
45 BAutolock lock(fLocker);
47 TRACE("RegisterBuffer team = %" B_PRId32 ", bufferid = %" B_PRId32 "\n",
48 team, bufferID);
50 buffer_info* info;
51 if (!fBufferInfoMap.Get(bufferID, info)) {
52 ERROR("failed to register buffer! team = %" B_PRId32 ", bufferid = %"
53 B_PRId32 "\n", team, bufferID);
54 return B_ERROR;
57 info->teams.insert(team);
59 *_area = info->area;
60 *_offset = info->offset;
61 *_size = info->size,
62 *_flags = info->flags;
64 return B_OK;
68 status_t
69 BufferManager::RegisterBuffer(team_id team, size_t size, int32 flags,
70 size_t offset, area_id area, media_buffer_id* _bufferID)
72 BAutolock lock(fLocker);
73 TRACE("RegisterBuffer team = %ld, area = %ld, offset = %ld, size = %ld\n",
74 team, area, offset, size);
76 area_id clonedArea = _CloneArea(area);
77 if (clonedArea < 0) {
78 ERROR("RegisterBuffer: failed to clone buffer! error = %#" B_PRIx32
79 ", team = %" B_PRId32 ", area = %" B_PRId32 ", offset = %"
80 B_PRIuSIZE ", size = %" B_PRIuSIZE "\n", clonedArea, team,
81 area, offset, size);
82 return clonedArea;
85 buffer_info info;
86 info.id = fNextBufferID++;
87 info.area = clonedArea;
88 info.offset = offset;
89 info.size = size;
90 info.flags = flags;
92 try {
93 info.teams.insert(team);
94 if (fBufferInfoMap.Put(info.id, info) != B_OK)
95 throw std::bad_alloc();
96 } catch (std::bad_alloc& exception) {
97 _ReleaseClonedArea(clonedArea);
98 return B_NO_MEMORY;
101 TRACE("RegisterBuffer: done, bufferID = %ld\n", info.id);
103 *_bufferID = info.id;
104 return B_OK;
108 status_t
109 BufferManager::UnregisterBuffer(team_id team, media_buffer_id bufferID)
111 BAutolock lock(fLocker);
112 TRACE("UnregisterBuffer: team = %" B_PRId32 ", bufferID = %" B_PRId32 "\n",
113 team, bufferID);
115 buffer_info* info;
116 if (!fBufferInfoMap.Get(bufferID, info)) {
117 ERROR("UnregisterBuffer: failed to unregister buffer! team = %"
118 B_PRId32 ", bufferID = %" B_PRId32 "\n", team, bufferID);
119 return B_ERROR;
122 if (info->teams.find(team) == info->teams.end()) {
123 ERROR("UnregisterBuffer: failed to find team = %" B_PRId32 " belonging"
124 " to bufferID = %" B_PRId32 "\n", team, bufferID);
125 return B_ERROR;
128 info->teams.erase(team);
130 TRACE("UnregisterBuffer: team = %" B_PRId32 " removed from bufferID = %"
131 B_PRId32 "\n", team, bufferID);
133 if (info->teams.empty()) {
134 _ReleaseClonedArea(info->area);
135 fBufferInfoMap.Remove(bufferID);
137 TRACE("UnregisterBuffer: bufferID = %" B_PRId32 " removed\n", bufferID);
140 return B_OK;
144 void
145 BufferManager::CleanupTeam(team_id team)
147 BAutolock lock(fLocker);
149 TRACE("BufferManager::CleanupTeam: team %" B_PRId32 "\n", team);
151 BufferInfoMap::Iterator iterator = fBufferInfoMap.GetIterator();
152 while (iterator.HasNext()) {
153 BufferInfoMap::Entry entry = iterator.Next();
155 entry.value.teams.erase(team);
157 if (entry.value.teams.empty()) {
158 PRINT(1, "BufferManager::CleanupTeam: removing buffer id %"
159 B_PRId32 " that has no teams\n", entry.key.GetHashCode());
160 _ReleaseClonedArea(entry.value.area);
161 iterator.Remove();
167 void
168 BufferManager::Dump()
170 BAutolock lock(fLocker);
172 printf("\n");
173 printf("BufferManager: list of buffers follows:\n");
175 BufferInfoMap::Iterator iterator = fBufferInfoMap.GetIterator();
176 while (iterator.HasNext()) {
177 buffer_info& info = *iterator.NextValue();
178 printf(" buffer-id %" B_PRId32 ", area-id %" B_PRId32 ", offset %ld, "
179 "size %ld, flags %#08" B_PRIx32 "\n", info.id, info.area,
180 info.offset, info.size, info.flags);
181 printf(" assigned teams: ");
183 std::set<team_id>::iterator teamIterator = info.teams.begin();
184 for (; teamIterator != info.teams.end(); teamIterator++) {
185 printf("%" B_PRId32 ", ", *teamIterator);
187 printf("\n");
189 printf("BufferManager: list end\n");
193 area_id
194 BufferManager::_CloneArea(area_id area)
197 clone_info* info;
198 if (fCloneInfoMap.Get(area, info)) {
199 // we have already cloned this particular area
200 TRACE("BufferManager::_CloneArea() area %" B_PRId32 " has already"
201 " been cloned (id %" B_PRId32 ")\n", area, info->clone);
203 info->ref_count++;
204 return info->clone;
208 void* address;
209 area_id clonedArea = clone_area("media_server cloned buffer", &address,
210 B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, area);
212 TRACE("BufferManager::_CloneArea() cloned area %" B_PRId32 ", clone id %"
213 B_PRId32 "\n", area, clonedArea);
215 if (clonedArea < 0)
216 return clonedArea;
218 clone_info info;
219 info.clone = clonedArea;
220 info.ref_count = 1;
222 if (fCloneInfoMap.Put(area, info) == B_OK) {
223 if (fSourceInfoMap.Put(clonedArea, area) == B_OK)
224 return clonedArea;
226 fCloneInfoMap.Remove(area);
229 delete_area(clonedArea);
230 return B_NO_MEMORY;
234 void
235 BufferManager::_ReleaseClonedArea(area_id clone)
237 area_id source = fSourceInfoMap.Get(clone);
239 clone_info* info;
240 if (!fCloneInfoMap.Get(source, info)) {
241 ERROR("BufferManager::_ReleaseClonedArea(): could not find clone info "
242 "for id %" B_PRId32 " (clone %" B_PRId32 ")\n", source, clone);
243 return;
246 if (--info->ref_count == 0) {
247 TRACE("BufferManager::_ReleaseClonedArea(): delete cloned area %"
248 B_PRId32 " (source %" B_PRId32 ")\n", clone, source);
250 fSourceInfoMap.Remove(clone);
251 fCloneInfoMap.Remove(source);
252 delete_area(clone);
253 } else {
254 TRACE("BufferManager::_ReleaseClonedArea(): released cloned area %"
255 B_PRId32 " (source %" B_PRId32 ")\n", clone, source);