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