xref: /haiku/src/servers/media/BufferManager.cpp (revision 51978af14a173e7fae0563b562be5603bc652aeb)
1 /*
2  * Copyright 2002, Marcus Overhagen. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 #include <MediaDefs.h>
6 #include <Autolock.h>
7 #include "BufferManager.h"
8 #include "SharedBufferList.h"
9 #include "debug.h"
10 
11 BufferManager::BufferManager()
12  :	fSharedBufferList(_shared_buffer_list::Clone()),
13 	fSharedBufferListId(-1),
14 	fNextBufferId(1),
15 	fLocker(new BLocker("buffer manager locker")),
16 	fBufferInfoMap(new Map<media_buffer_id, buffer_info>)
17 {
18 	fSharedBufferListId = area_for(fSharedBufferList);
19 }
20 
21 BufferManager::~BufferManager()
22 {
23 	fSharedBufferList->Unmap();
24 	delete fLocker;
25 	delete fBufferInfoMap;
26 }
27 
28 area_id
29 BufferManager::SharedBufferListID()
30 {
31 	return fSharedBufferListId;
32 }
33 
34 status_t
35 BufferManager::RegisterBuffer(team_id teamid, media_buffer_id bufferid,
36 							  size_t *size, int32 *flags, size_t *offset, area_id *area)
37 {
38 	BAutolock lock(fLocker);
39 
40 	TRACE("RegisterBuffer team = %ld, bufferid = %ld\n", teamid, bufferid);
41 
42 	buffer_info *info;
43 	if (!fBufferInfoMap->Get(bufferid, &info)) {
44 		ERROR("failed to register buffer! team = %ld, bufferid = %ld\n", teamid, bufferid);
45 		return B_ERROR;
46 	}
47 
48 	info->teams.Insert(teamid);
49 
50 	*area 	= info->area;
51 	*offset	= info->offset;
52 	*size 	= info->size,
53 	*flags 	= info->flags;
54 	return B_OK;
55 }
56 
57 status_t
58 BufferManager::RegisterBuffer(team_id teamid, size_t size, int32 flags, size_t offset, area_id area,
59 							  media_buffer_id *bufferid)
60 {
61 	BAutolock lock(fLocker);
62 	TRACE("RegisterBuffer team = %ld, areaid = %ld, offset = %ld, size = %ld\n", teamid, area, offset, size);
63 
64 	void *adr;
65 	area_id newarea;
66 
67 	newarea = clone_area("media_server cloned buffer", &adr, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, area);
68 	if (newarea <= B_OK) {
69 		ERROR("RegisterBuffer: failed to clone buffer! error = %#lx, team = %ld, areaid = %ld, offset = %ld, size = %ld\n", newarea, teamid, area, offset, size);
70 		return B_ERROR;
71 	}
72 
73 	buffer_info info;
74 
75 	*bufferid	= fNextBufferId;
76 	info.id 	= fNextBufferId;
77 	info.area 	= newarea;
78 	info.offset = offset;
79 	info.size 	= size;
80 	info.flags	= flags;
81 	info.teams.Insert(teamid);
82 	fBufferInfoMap->Insert(fNextBufferId, info);
83 
84 	TRACE("RegisterBuffer: done, bufferid = %ld\n", fNextBufferId);
85 
86 	fNextBufferId += 1;
87 
88 	return B_OK;
89 }
90 
91 status_t
92 BufferManager::UnregisterBuffer(team_id teamid, media_buffer_id bufferid)
93 {
94 	BAutolock lock(fLocker);
95 	TRACE("UnregisterBuffer: team = %ld, bufferid = %ld\n", teamid, bufferid);
96 
97 	buffer_info *info;
98 	int index;
99 
100 	if (!fBufferInfoMap->Get(bufferid, &info)) {
101 		ERROR("UnregisterBuffer: failed to unregister buffer! team = %ld, bufferid = %ld\n", teamid, bufferid);
102 		return B_ERROR;
103 	}
104 
105 	index = info->teams.Find(teamid);
106 	if (index < 0) {
107 		ERROR("UnregisterBuffer: failed to find team = %ld belonging to bufferid = %ld\n", teamid, bufferid);
108 		return B_ERROR;
109 	}
110 
111 	if (!info->teams.Remove(index)) {
112 		ERROR("UnregisterBuffer: failed to remove team = %ld from bufferid = %ld\n", teamid, bufferid);
113 		return B_ERROR;
114 	}
115 	TRACE("UnregisterBuffer: team = %ld removed from bufferid = %ld\n", teamid, bufferid);
116 
117 	if (info->teams.IsEmpty()) {
118 
119 		if (!fBufferInfoMap->Remove(bufferid)) {
120 			ERROR("UnregisterBuffer: failed to remove bufferid = %ld\n", bufferid);
121 			return B_ERROR;
122 		}
123 
124 		TRACE("UnregisterBuffer: bufferid = %ld removed\n", bufferid);
125 	}
126 
127 	return B_OK;
128 }
129 
130 void
131 BufferManager::CleanupTeam(team_id team)
132 {
133 	BAutolock lock(fLocker);
134 	buffer_info *info;
135 
136 	TRACE("BufferManager::CleanupTeam: team %ld\n", team);
137 
138 	for (fBufferInfoMap->Rewind(); fBufferInfoMap->GetNext(&info); ) {
139 		team_id *otherteam;
140 		for (info->teams.Rewind(); info->teams.GetNext(&otherteam); ) {
141 			if (team == *otherteam) {
142 				PRINT(1, "BufferManager::CleanupTeam: removing team %ld from buffer id %ld\n", team, info->id);
143 				info->teams.RemoveCurrent();
144 			}
145 		}
146 		if (info->teams.IsEmpty()) {
147 			PRINT(1, "BufferManager::CleanupTeam: removing buffer id %ld that has no teams\n", info->id);
148 			fBufferInfoMap->RemoveCurrent();
149 		}
150 	}
151 }
152 
153 void
154 BufferManager::Dump()
155 {
156 	BAutolock lock(fLocker);
157 	buffer_info *info;
158 	printf("\n");
159 	printf("BufferManager: list of buffers follows:\n");
160 	for (fBufferInfoMap->Rewind(); fBufferInfoMap->GetNext(&info); ) {
161 		printf(" buffer-id %ld, area-id %ld, offset %ld, size %ld, flags %#08lx\n",
162 			 info->id, info->area, info->offset, info->size, info->flags);
163 		printf("   assigned teams: ");
164 		team_id *team;
165 		for (info->teams.Rewind(); info->teams.GetNext(&team); ) {
166 			printf("%ld, ", *team);
167 		}
168 		printf("\n");
169 	}
170 	printf("BufferManager: list end\n");
171 }
172