xref: /haiku/src/servers/media/BufferManager.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
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 
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 
28 BufferManager::~BufferManager()
29 {
30 	fSharedBufferList->Put();
31 }
32 
33 
34 area_id
35 BufferManager::SharedBufferListArea()
36 {
37 	return fSharedBufferListArea;
38 }
39 
40 
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)
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
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
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
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
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
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
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