xref: /haiku/src/system/kernel/fs/Vnode.cpp (revision 8e8f7748d39f8407894a5ab79f7b4f93bc4f4652)
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