/* * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #include "Vnode.h" #include vnode::Bucket vnode::sBuckets[kBucketCount]; vnode::Bucket::Bucket() { mutex_init(&lock, "vnode bucket"); } /*static*/ void vnode::StaticInit() { for (uint32 i = 0; i < kBucketCount; i++) new(&sBuckets[i]) Bucket; } void vnode::_WaitForLock() { LockWaiter waiter; waiter.thread = thread_get_current_thread(); waiter.vnode = this; Bucket& bucket = _Bucket(); MutexLocker bucketLocker(bucket.lock); if ((atomic_or(&fFlags, kFlagsWaitingLocker) & (kFlagsLocked | kFlagsWaitingLocker)) == 0) { // The lock holder dropped it in the meantime and no-one else was faster // than us, so it's ours now. Just mark the node locked and clear the // waiting flag again. atomic_or(&fFlags, kFlagsLocked); atomic_and(&fFlags, ~kFlagsWaitingLocker); return; } // prepare for waiting bucket.waiters.Add(&waiter); thread_prepare_to_block(waiter.thread, 0, THREAD_BLOCK_TYPE_OTHER, "vnode lock"); // start waiting bucketLocker.Unlock(); thread_block(); } void vnode::_WakeUpLocker() { Bucket& bucket = _Bucket(); MutexLocker bucketLocker(bucket.lock); // mark the node locked again atomic_or(&fFlags, kFlagsLocked); // get the first waiter from the list LockWaiter* waiter = NULL; bool onlyWaiter = true; for (LockWaiterList::Iterator it = bucket.waiters.GetIterator(); LockWaiter* someWaiter = it.Next();) { if (someWaiter->vnode == this) { if (waiter != NULL) { onlyWaiter = false; break; } waiter = someWaiter; it.Remove(); } } ASSERT(waiter != NULL); // if that's the only waiter, clear the flag if (onlyWaiter) atomic_and(&fFlags, ~kFlagsWaitingLocker); // and wake it up thread_unblock(waiter->thread, B_OK); }