// NodeHandleMap.cpp #include "NodeHandleMap.h" #include "AutoLocker.h" #include "GlobalBlockerPool.h" // constructor NodeHandleMap::NodeHandleMap(const char* name) : Locker(name), fNextNodeHandleCookie(0) { } // destructor NodeHandleMap::~NodeHandleMap() { } // Init status_t NodeHandleMap::Init() { // check semaphore if (Sem() < 0) return Sem(); return B_OK; } // AddNodeHandle status_t NodeHandleMap::AddNodeHandle(NodeHandle* handle) { if (!handle) return B_BAD_VALUE; AutoLocker _(this); handle->SetCookie(_NextNodeHandleCookie()); status_t error = Put(handle->GetCookie(), handle); if (error == B_OK) handle->AcquireReference(); return error; } // RemoveNodeHandle bool NodeHandleMap::RemoveNodeHandle(NodeHandle* handle) { if (!handle) return false; AutoLocker _(this); if (Get(handle->GetCookie()) != handle) return false; Remove(handle->GetCookie()); handle->ReleaseReference(); return true; } // LockNodeHandle // // VolumeManager must NOT be locked. status_t NodeHandleMap::LockNodeHandle(int32 cookie, NodeHandle** _handle) { if (!_handle) return B_BAD_VALUE; NodeHandle* handle; { AutoLocker _(this); // get the node handle handle = Get(cookie); if (!handle) return B_ENTRY_NOT_FOUND; handle->AcquireReference(); // first attempt: we just try to lock the node handle, which will fail, // if someone else has the lock at the momemt if (handle->Lock()) { *_handle = handle; return B_OK; } } // someone else is locking, get a blocker and wait for the lock BlockerPool* blockerPool = GlobalBlockerPool::GetDefault(); Blocker blocker = blockerPool->GetBlocker(); BlockerPutter blockerPutter(*blockerPool, blocker); LockerCandidate lockerCandidate(blocker); { AutoLocker _(this); if (handle->Lock()) { *_handle = handle; return B_OK; } handle->QueueLockerCandidate(&lockerCandidate); } // wait for the lock status_t error = lockerCandidate.Block(); if (error != B_OK) { handle->ReleaseReference(); return error; } *_handle = handle; return B_OK; } // UnlockNodeHandle // // VolumeManager may or may not be locked. void NodeHandleMap::UnlockNodeHandle(NodeHandle* nodeHandle) { if (!nodeHandle) return; if (nodeHandle->IsLocked()) { AutoLocker _(this); nodeHandle->Unlock(); nodeHandle->ReleaseReference(); } } // _NextNodeHandleCookie int32 NodeHandleMap::_NextNodeHandleCookie() { int32 cookie; do { if (fNextNodeHandleCookie < 0) fNextNodeHandleCookie = 0; cookie = fNextNodeHandleCookie++; } while (ContainsKey(cookie)); return cookie; }