1 /* 2 * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "Vnode.h" 8 9 #include <util/AutoLock.h> 10 11 12 vnode::Bucket vnode::sBuckets[kBucketCount]; 13 14 15 vnode::Bucket::Bucket() 16 { 17 mutex_init(&lock, "vnode bucket"); 18 } 19 20 21 /*static*/ void 22 vnode::StaticInit() 23 { 24 for (uint32 i = 0; i < kBucketCount; i++) 25 new(&sBuckets[i]) Bucket; 26 } 27 28 29 void 30 vnode::_WaitForLock() 31 { 32 LockWaiter waiter; 33 waiter.thread = thread_get_current_thread(); 34 waiter.vnode = this; 35 36 Bucket& bucket = _Bucket(); 37 MutexLocker bucketLocker(bucket.lock); 38 39 if ((atomic_or(&fFlags, kFlagsWaitingLocker) 40 & (kFlagsLocked | kFlagsWaitingLocker)) == 0) { 41 // The lock holder dropped it in the meantime and no-one else was faster 42 // than us, so it's ours now. Just mark the node locked and clear the 43 // waiting flag again. 44 atomic_or(&fFlags, kFlagsLocked); 45 atomic_and(&fFlags, ~kFlagsWaitingLocker); 46 return; 47 } 48 49 // prepare for waiting 50 bucket.waiters.Add(&waiter); 51 thread_prepare_to_block(waiter.thread, 0, THREAD_BLOCK_TYPE_OTHER, 52 "vnode lock"); 53 54 // start waiting 55 bucketLocker.Unlock(); 56 thread_block(); 57 } 58 59 60 void 61 vnode::_WakeUpLocker() 62 { 63 Bucket& bucket = _Bucket(); 64 MutexLocker bucketLocker(bucket.lock); 65 66 // mark the node locked again 67 atomic_or(&fFlags, kFlagsLocked); 68 69 // get the first waiter from the list 70 LockWaiter* waiter = NULL; 71 bool onlyWaiter = true; 72 for (LockWaiterList::Iterator it = bucket.waiters.GetIterator(); 73 LockWaiter* someWaiter = it.Next();) { 74 if (someWaiter->vnode == this) { 75 if (waiter != NULL) { 76 onlyWaiter = false; 77 break; 78 } 79 waiter = someWaiter; 80 it.Remove(); 81 } 82 } 83 84 ASSERT(waiter != NULL); 85 86 // if that's the only waiter, clear the flag 87 if (onlyWaiter) 88 atomic_and(&fFlags, ~kFlagsWaitingLocker); 89 90 // and wake it up 91 thread_unblock(waiter->thread, B_OK); 92 } 93