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