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