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
Bucket()15 vnode::Bucket::Bucket()
16 {
17 mutex_init(&lock, "vnode bucket");
18 }
19
20
21 /*static*/ void
StaticInit()22 vnode::StaticInit()
23 {
24 for (uint32 i = 0; i < kBucketCount; i++)
25 new(&sBuckets[i]) Bucket;
26 }
27
28
29 void
_WaitForLock()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
_WakeUpLocker()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