/* * Copyright 2002, Marcus Overhagen. All rights reserved. * Copyright 2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ #include "BufferManager.h" #include #include "MediaDebug.h" #include "SharedBufferList.h" BufferManager::BufferManager() : fSharedBufferList(NULL), fSharedBufferListArea(-1), fNextBufferID(1), fLocker("buffer manager locker") { fSharedBufferListArea = BPrivate::SharedBufferList::Create(&fSharedBufferList); } BufferManager::~BufferManager() { fSharedBufferList->Put(); } area_id BufferManager::SharedBufferListArea() { return fSharedBufferListArea; } status_t BufferManager::RegisterBuffer(team_id team, media_buffer_id bufferID, size_t* _size, int32* _flags, size_t* _offset, area_id* _area) { BAutolock lock(fLocker); TRACE("RegisterBuffer team = %" B_PRId32 ", bufferid = %" B_PRId32 "\n", team, bufferID); buffer_info* info; if (!fBufferInfoMap.Get(bufferID, info)) { ERROR("failed to register buffer! team = %" B_PRId32 ", bufferid = %" B_PRId32 "\n", team, bufferID); return B_ERROR; } info->teams.insert(team); *_area = info->area; *_offset = info->offset; *_size = info->size, *_flags = info->flags; return B_OK; } status_t BufferManager::RegisterBuffer(team_id team, size_t size, int32 flags, size_t offset, area_id area, media_buffer_id* _bufferID) { BAutolock lock(fLocker); TRACE("RegisterBuffer team = %" B_PRId32 ", area = %" B_PRId32 ", offset = %" B_PRIuSIZE ", size = %" B_PRIuSIZE "\n", team, area, offset, size); area_id clonedArea = _CloneArea(area); if (clonedArea < 0) { ERROR("RegisterBuffer: failed to clone buffer! error = %#" B_PRIx32 ", team = %" B_PRId32 ", area = %" B_PRId32 ", offset = %" B_PRIuSIZE ", size = %" B_PRIuSIZE "\n", clonedArea, team, area, offset, size); return clonedArea; } buffer_info info; info.id = fNextBufferID++; info.area = clonedArea; info.offset = offset; info.size = size; info.flags = flags; try { info.teams.insert(team); if (fBufferInfoMap.Put(info.id, info) != B_OK) throw std::bad_alloc(); } catch (std::bad_alloc& exception) { _ReleaseClonedArea(clonedArea); return B_NO_MEMORY; } TRACE("RegisterBuffer: done, bufferID = %" B_PRId32 "\n", info.id); *_bufferID = info.id; return B_OK; } status_t BufferManager::UnregisterBuffer(team_id team, media_buffer_id bufferID) { BAutolock lock(fLocker); TRACE("UnregisterBuffer: team = %" B_PRId32 ", bufferID = %" B_PRId32 "\n", team, bufferID); buffer_info* info; if (!fBufferInfoMap.Get(bufferID, info)) { ERROR("UnregisterBuffer: failed to unregister buffer! team = %" B_PRId32 ", bufferID = %" B_PRId32 "\n", team, bufferID); return B_ERROR; } if (info->teams.find(team) == info->teams.end()) { ERROR("UnregisterBuffer: failed to find team = %" B_PRId32 " belonging" " to bufferID = %" B_PRId32 "\n", team, bufferID); return B_ERROR; } info->teams.erase(team); TRACE("UnregisterBuffer: team = %" B_PRId32 " removed from bufferID = %" B_PRId32 "\n", team, bufferID); if (info->teams.empty()) { _ReleaseClonedArea(info->area); fBufferInfoMap.Remove(bufferID); TRACE("UnregisterBuffer: bufferID = %" B_PRId32 " removed\n", bufferID); } return B_OK; } void BufferManager::CleanupTeam(team_id team) { BAutolock lock(fLocker); TRACE("BufferManager::CleanupTeam: team %" B_PRId32 "\n", team); BufferInfoMap::Iterator iterator = fBufferInfoMap.GetIterator(); while (iterator.HasNext()) { BufferInfoMap::Entry entry = iterator.Next(); entry.value.teams.erase(team); if (entry.value.teams.empty()) { PRINT(1, "BufferManager::CleanupTeam: removing buffer id %" B_PRId32 " that has no teams\n", entry.key.GetHashCode()); _ReleaseClonedArea(entry.value.area); fBufferInfoMap.Remove(iterator); } } } void BufferManager::Dump() { BAutolock lock(fLocker); printf("\n"); printf("BufferManager: list of buffers follows:\n"); BufferInfoMap::Iterator iterator = fBufferInfoMap.GetIterator(); while (iterator.HasNext()) { buffer_info info = iterator.Next().value; printf(" buffer-id %" B_PRId32 ", area-id %" B_PRId32 ", offset %ld, " "size %ld, flags %#08" B_PRIx32 "\n", info.id, info.area, info.offset, info.size, info.flags); printf(" assigned teams: "); std::set::iterator teamIterator = info.teams.begin(); for (; teamIterator != info.teams.end(); teamIterator++) { printf("%" B_PRId32 ", ", *teamIterator); } printf("\n"); } printf("BufferManager: list end\n"); } area_id BufferManager::_CloneArea(area_id area) { { clone_info* info; if (fCloneInfoMap.Get(area, info)) { // we have already cloned this particular area TRACE("BufferManager::_CloneArea() area %" B_PRId32 " has already" " been cloned (id %" B_PRId32 ")\n", area, info->clone); info->ref_count++; return info->clone; } } void* address; area_id clonedArea = clone_area("media_server cloned buffer", &address, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA | B_CLONEABLE_AREA, area); TRACE("BufferManager::_CloneArea() cloned area %" B_PRId32 ", clone id %" B_PRId32 "\n", area, clonedArea); if (clonedArea < 0) return clonedArea; clone_info info; info.clone = clonedArea; info.ref_count = 1; if (fCloneInfoMap.Put(area, info) == B_OK) { if (fSourceInfoMap.Put(clonedArea, area) == B_OK) return clonedArea; fCloneInfoMap.Remove(area); } delete_area(clonedArea); return B_NO_MEMORY; } void BufferManager::_ReleaseClonedArea(area_id clone) { area_id source = fSourceInfoMap.Get(clone); clone_info* info; if (!fCloneInfoMap.Get(source, info)) { ERROR("BufferManager::_ReleaseClonedArea(): could not find clone info " "for id %" B_PRId32 " (clone %" B_PRId32 ")\n", source, clone); return; } if (--info->ref_count == 0) { TRACE("BufferManager::_ReleaseClonedArea(): delete cloned area %" B_PRId32 " (source %" B_PRId32 ")\n", clone, source); fSourceInfoMap.Remove(clone); fCloneInfoMap.Remove(source); delete_area(clone); } else { TRACE("BufferManager::_ReleaseClonedArea(): released cloned area %" B_PRId32 " (source %" B_PRId32 ")\n", clone, source); } }