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