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