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 */
6
7
8 #include "BufferManager.h"
9
10 #include <Autolock.h>
11
12 #include "MediaDebug.h"
13 #include "SharedBufferList.h"
14
15
BufferManager()16 BufferManager::BufferManager()
17 :
18 fSharedBufferList(NULL),
19 fSharedBufferListArea(-1),
20 fNextBufferID(1),
21 fLocker("buffer manager locker")
22 {
23 fSharedBufferListArea
24 = BPrivate::SharedBufferList::Create(&fSharedBufferList);
25 }
26
27
~BufferManager()28 BufferManager::~BufferManager()
29 {
30 fSharedBufferList->Put();
31 }
32
33
34 area_id
SharedBufferListArea()35 BufferManager::SharedBufferListArea()
36 {
37 return fSharedBufferListArea;
38 }
39
40
41 status_t
RegisterBuffer(team_id team,media_buffer_id bufferID,size_t * _size,int32 * _flags,size_t * _offset,area_id * _area)42 BufferManager::RegisterBuffer(team_id team, media_buffer_id bufferID,
43 size_t* _size, int32* _flags, size_t* _offset, area_id* _area)
44 {
45 BAutolock lock(fLocker);
46
47 TRACE("RegisterBuffer team = %" B_PRId32 ", bufferid = %" B_PRId32 "\n",
48 team, bufferID);
49
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;
55 }
56
57 info->teams.insert(team);
58
59 *_area = info->area;
60 *_offset = info->offset;
61 *_size = info->size,
62 *_flags = info->flags;
63
64 return B_OK;
65 }
66
67
68 status_t
RegisterBuffer(team_id team,size_t size,int32 flags,size_t offset,area_id area,media_buffer_id * _bufferID)69 BufferManager::RegisterBuffer(team_id team, size_t size, int32 flags,
70 size_t offset, area_id area, media_buffer_id* _bufferID)
71 {
72 BAutolock lock(fLocker);
73 TRACE("RegisterBuffer team = %" B_PRId32 ", area = %"
74 B_PRId32 ", offset = %" B_PRIuSIZE ", size = %" B_PRIuSIZE "\n",
75 team, area, offset, size);
76
77 area_id clonedArea = _CloneArea(area);
78 if (clonedArea < 0) {
79 ERROR("RegisterBuffer: failed to clone buffer! error = %#" B_PRIx32
80 ", team = %" B_PRId32 ", area = %" B_PRId32 ", offset = %"
81 B_PRIuSIZE ", size = %" B_PRIuSIZE "\n", clonedArea, team,
82 area, offset, size);
83 return clonedArea;
84 }
85
86 buffer_info info;
87 info.id = fNextBufferID++;
88 info.area = clonedArea;
89 info.offset = offset;
90 info.size = size;
91 info.flags = flags;
92
93 try {
94 info.teams.insert(team);
95 if (fBufferInfoMap.Put(info.id, info) != B_OK)
96 throw std::bad_alloc();
97 } catch (std::bad_alloc& exception) {
98 _ReleaseClonedArea(clonedArea);
99 return B_NO_MEMORY;
100 }
101
102 TRACE("RegisterBuffer: done, bufferID = %" B_PRId32 "\n", info.id);
103
104 *_bufferID = info.id;
105 return B_OK;
106 }
107
108
109 status_t
UnregisterBuffer(team_id team,media_buffer_id bufferID)110 BufferManager::UnregisterBuffer(team_id team, media_buffer_id bufferID)
111 {
112 BAutolock lock(fLocker);
113 TRACE("UnregisterBuffer: team = %" B_PRId32 ", bufferID = %" B_PRId32 "\n",
114 team, bufferID);
115
116 buffer_info* info;
117 if (!fBufferInfoMap.Get(bufferID, info)) {
118 ERROR("UnregisterBuffer: failed to unregister buffer! team = %"
119 B_PRId32 ", bufferID = %" B_PRId32 "\n", team, bufferID);
120 return B_ERROR;
121 }
122
123 if (info->teams.find(team) == info->teams.end()) {
124 ERROR("UnregisterBuffer: failed to find team = %" B_PRId32 " belonging"
125 " to bufferID = %" B_PRId32 "\n", team, bufferID);
126 return B_ERROR;
127 }
128
129 info->teams.erase(team);
130
131 TRACE("UnregisterBuffer: team = %" B_PRId32 " removed from bufferID = %"
132 B_PRId32 "\n", team, bufferID);
133
134 if (info->teams.empty()) {
135 _ReleaseClonedArea(info->area);
136 fBufferInfoMap.Remove(bufferID);
137
138 TRACE("UnregisterBuffer: bufferID = %" B_PRId32 " removed\n", bufferID);
139 }
140
141 return B_OK;
142 }
143
144
145 void
CleanupTeam(team_id team)146 BufferManager::CleanupTeam(team_id team)
147 {
148 BAutolock lock(fLocker);
149
150 TRACE("BufferManager::CleanupTeam: team %" B_PRId32 "\n", team);
151
152 BufferInfoMap::Iterator iterator = fBufferInfoMap.GetIterator();
153 while (iterator.HasNext()) {
154 BufferInfoMap::Entry entry = iterator.Next();
155
156 entry.value.teams.erase(team);
157
158 if (entry.value.teams.empty()) {
159 PRINT(1, "BufferManager::CleanupTeam: removing buffer id %"
160 B_PRId32 " that has no teams\n", entry.key.GetHashCode());
161 _ReleaseClonedArea(entry.value.area);
162 fBufferInfoMap.Remove(iterator);
163 }
164 }
165 }
166
167
168 void
Dump()169 BufferManager::Dump()
170 {
171 BAutolock lock(fLocker);
172
173 printf("\n");
174 printf("BufferManager: list of buffers follows:\n");
175
176 BufferInfoMap::Iterator iterator = fBufferInfoMap.GetIterator();
177 while (iterator.HasNext()) {
178 buffer_info info = iterator.Next().value;
179 printf(" buffer-id %" B_PRId32 ", area-id %" B_PRId32 ", offset %ld, "
180 "size %ld, flags %#08" B_PRIx32 "\n", info.id, info.area,
181 info.offset, info.size, info.flags);
182 printf(" assigned teams: ");
183
184 std::set<team_id>::iterator teamIterator = info.teams.begin();
185 for (; teamIterator != info.teams.end(); teamIterator++) {
186 printf("%" B_PRId32 ", ", *teamIterator);
187 }
188 printf("\n");
189 }
190 printf("BufferManager: list end\n");
191 }
192
193
194 area_id
_CloneArea(area_id area)195 BufferManager::_CloneArea(area_id area)
196 {
197 {
198 clone_info* info;
199 if (fCloneInfoMap.Get(area, info)) {
200 // we have already cloned this particular area
201 TRACE("BufferManager::_CloneArea() area %" B_PRId32 " has already"
202 " been cloned (id %" B_PRId32 ")\n", area, info->clone);
203
204 info->ref_count++;
205 return info->clone;
206 }
207 }
208
209 void* address;
210 area_id clonedArea = clone_area("media_server cloned buffer", &address,
211 B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA | B_CLONEABLE_AREA, area);
212
213 TRACE("BufferManager::_CloneArea() cloned area %" B_PRId32 ", clone id %"
214 B_PRId32 "\n", area, clonedArea);
215
216 if (clonedArea < 0)
217 return clonedArea;
218
219 clone_info info;
220 info.clone = clonedArea;
221 info.ref_count = 1;
222
223 if (fCloneInfoMap.Put(area, info) == B_OK) {
224 if (fSourceInfoMap.Put(clonedArea, area) == B_OK)
225 return clonedArea;
226
227 fCloneInfoMap.Remove(area);
228 }
229
230 delete_area(clonedArea);
231 return B_NO_MEMORY;
232 }
233
234
235 void
_ReleaseClonedArea(area_id clone)236 BufferManager::_ReleaseClonedArea(area_id clone)
237 {
238 area_id source = fSourceInfoMap.Get(clone);
239
240 clone_info* info;
241 if (!fCloneInfoMap.Get(source, info)) {
242 ERROR("BufferManager::_ReleaseClonedArea(): could not find clone info "
243 "for id %" B_PRId32 " (clone %" B_PRId32 ")\n", source, clone);
244 return;
245 }
246
247 if (--info->ref_count == 0) {
248 TRACE("BufferManager::_ReleaseClonedArea(): delete cloned area %"
249 B_PRId32 " (source %" B_PRId32 ")\n", clone, source);
250
251 fSourceInfoMap.Remove(clone);
252 fCloneInfoMap.Remove(source);
253 delete_area(clone);
254 } else {
255 TRACE("BufferManager::_ReleaseClonedArea(): released cloned area %"
256 B_PRId32 " (source %" B_PRId32 ")\n", clone, source);
257 }
258 }
259