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