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(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 = %ld, area = %ld, offset = %ld, size = %ld\n", 74 team, area, offset, size); 75 76 area_id clonedArea = _CloneArea(area); 77 if (clonedArea < 0) { 78 ERROR("RegisterBuffer: failed to clone buffer! error = %#" B_PRIx32 79 ", team = %" B_PRId32 ", area = %" B_PRId32 ", offset = %" 80 B_PRIuSIZE ", size = %" B_PRIuSIZE "\n", clonedArea, team, 81 area, offset, size); 82 return clonedArea; 83 } 84 85 buffer_info info; 86 info.id = fNextBufferID++; 87 info.area = clonedArea; 88 info.offset = offset; 89 info.size = size; 90 info.flags = flags; 91 92 try { 93 info.teams.insert(team); 94 if (fBufferInfoMap.Put(info.id, info) != B_OK) 95 throw std::bad_alloc(); 96 } catch (std::bad_alloc& exception) { 97 _ReleaseClonedArea(clonedArea); 98 return B_NO_MEMORY; 99 } 100 101 TRACE("RegisterBuffer: done, bufferID = %ld\n", info.id); 102 103 *_bufferID = info.id; 104 return B_OK; 105 } 106 107 108 status_t 109 BufferManager::UnregisterBuffer(team_id team, media_buffer_id bufferID) 110 { 111 BAutolock lock(fLocker); 112 TRACE("UnregisterBuffer: team = %" B_PRId32 ", bufferID = %" B_PRId32 "\n", 113 team, bufferID); 114 115 buffer_info* info; 116 if (!fBufferInfoMap.Get(bufferID, info)) { 117 ERROR("UnregisterBuffer: failed to unregister buffer! team = %" 118 B_PRId32 ", bufferID = %" B_PRId32 "\n", team, bufferID); 119 return B_ERROR; 120 } 121 122 if (info->teams.find(team) == info->teams.end()) { 123 ERROR("UnregisterBuffer: failed to find team = %" B_PRId32 " belonging" 124 " to bufferID = %" B_PRId32 "\n", team, bufferID); 125 return B_ERROR; 126 } 127 128 info->teams.erase(team); 129 130 TRACE("UnregisterBuffer: team = %" B_PRId32 " removed from bufferID = %" 131 B_PRId32 "\n", team, bufferID); 132 133 if (info->teams.empty()) { 134 _ReleaseClonedArea(info->area); 135 fBufferInfoMap.Remove(bufferID); 136 137 TRACE("UnregisterBuffer: bufferID = %" B_PRId32 " removed\n", bufferID); 138 } 139 140 return B_OK; 141 } 142 143 144 void 145 BufferManager::CleanupTeam(team_id team) 146 { 147 BAutolock lock(fLocker); 148 149 TRACE("BufferManager::CleanupTeam: team %" B_PRId32 "\n", team); 150 151 BufferInfoMap::Iterator iterator = fBufferInfoMap.GetIterator(); 152 while (iterator.HasNext()) { 153 BufferInfoMap::Entry entry = iterator.Next(); 154 155 entry.value.teams.erase(team); 156 157 if (entry.value.teams.empty()) { 158 PRINT(1, "BufferManager::CleanupTeam: removing buffer id %" 159 B_PRId32 " that has no teams\n", entry.key.GetHashCode()); 160 _ReleaseClonedArea(entry.value.area); 161 iterator.Remove(); 162 } 163 } 164 } 165 166 167 void 168 BufferManager::Dump() 169 { 170 BAutolock lock(fLocker); 171 172 printf("\n"); 173 printf("BufferManager: list of buffers follows:\n"); 174 175 BufferInfoMap::Iterator iterator = fBufferInfoMap.GetIterator(); 176 while (iterator.HasNext()) { 177 buffer_info& info = *iterator.NextValue(); 178 printf(" buffer-id %" B_PRId32 ", area-id %" B_PRId32 ", offset %ld, " 179 "size %ld, flags %#08" B_PRIx32 "\n", info.id, info.area, 180 info.offset, info.size, info.flags); 181 printf(" assigned teams: "); 182 183 std::set<team_id>::iterator teamIterator = info.teams.begin(); 184 for (; teamIterator != info.teams.end(); teamIterator++) { 185 printf("%" B_PRId32 ", ", *teamIterator); 186 } 187 printf("\n"); 188 } 189 printf("BufferManager: list end\n"); 190 } 191 192 193 area_id 194 BufferManager::_CloneArea(area_id area) 195 { 196 { 197 clone_info* info; 198 if (fCloneInfoMap.Get(area, info)) { 199 // we have already cloned this particular area 200 TRACE("BufferManager::_CloneArea() area %" B_PRId32 " has already" 201 " been cloned (id %" B_PRId32 ")\n", area, info->clone); 202 203 info->ref_count++; 204 return info->clone; 205 } 206 } 207 208 void* address; 209 area_id clonedArea = clone_area("media_server cloned buffer", &address, 210 B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, area); 211 212 TRACE("BufferManager::_CloneArea() cloned area %" B_PRId32 ", clone id %" 213 B_PRId32 "\n", area, clonedArea); 214 215 if (clonedArea < 0) 216 return clonedArea; 217 218 clone_info info; 219 info.clone = clonedArea; 220 info.ref_count = 1; 221 222 if (fCloneInfoMap.Put(area, info) == B_OK) { 223 if (fSourceInfoMap.Put(clonedArea, area) == B_OK) 224 return clonedArea; 225 226 fCloneInfoMap.Remove(area); 227 } 228 229 delete_area(clonedArea); 230 return B_NO_MEMORY; 231 } 232 233 234 void 235 BufferManager::_ReleaseClonedArea(area_id clone) 236 { 237 area_id source = fSourceInfoMap.Get(clone); 238 239 clone_info* info; 240 if (!fCloneInfoMap.Get(source, info)) { 241 ERROR("BufferManager::_ReleaseClonedArea(): could not find clone info " 242 "for id %" B_PRId32 " (clone %" B_PRId32 ")\n", source, clone); 243 return; 244 } 245 246 if (--info->ref_count == 0) { 247 TRACE("BufferManager::_ReleaseClonedArea(): delete cloned area %" 248 B_PRId32 " (source %" B_PRId32 ")\n", clone, source); 249 250 fSourceInfoMap.Remove(clone); 251 fCloneInfoMap.Remove(source); 252 delete_area(clone); 253 } else { 254 TRACE("BufferManager::_ReleaseClonedArea(): released cloned area %" 255 B_PRId32 " (source %" B_PRId32 ")\n", clone, source); 256 } 257 } 258