1// Lockable.cpp
2
3#include "Lockable.h"
4
5
6// LockerCandidate
7
8// constructor
9LockerCandidate::LockerCandidate(Blocker blocker)
10	: fBlocker(blocker),
11	  fThread(find_thread(NULL))
12{
13}
14
15// GetThread
16thread_id
17LockerCandidate::GetThread() const
18{
19	return fThread;
20}
21
22// Block
23status_t
24LockerCandidate::Block()
25{
26	int32 userData;
27	status_t error = fBlocker.Block(&userData);
28	if (error != B_OK)
29		return error;
30
31	return (userData ? B_OK : B_ENTRY_NOT_FOUND);
32}
33
34// Unblock
35status_t
36LockerCandidate::Unblock(bool success)
37{
38	return fBlocker.Unblock(success);
39}
40
41
42// #pragma mark -
43
44// Lockable
45
46// constructor
47Lockable::Lockable()
48	: fLockOwner(-1),
49	  fLockCounter(0)
50{
51}
52
53// destructor
54Lockable::~Lockable()
55{
56	// unblock all
57	while (LockerCandidate* candidate = fLockerCandidates.First()) {
58		fLockerCandidates.Remove(candidate);
59		candidate->Unblock(false);
60	}
61}
62
63// Lock
64bool
65Lockable::Lock()
66{
67	thread_id thread = find_thread(NULL);
68	if (fLockOwner >= 0 && fLockOwner != thread)
69		return false;
70	fLockOwner = thread;
71	fLockCounter++;
72	return true;
73}
74
75// Unlock
76void
77Lockable::Unlock()
78{
79	thread_id thread = find_thread(NULL);
80	if (fLockOwner != thread)
81		return;
82	if (--fLockCounter > 0)
83		return;
84	if (LockerCandidate* candidate = fLockerCandidates.First()) {
85		fLockerCandidates.Remove(candidate);
86		fLockOwner = candidate->GetThread();
87		fLockCounter = 1;
88		candidate->Unblock(true);
89	} else
90		fLockOwner = -1;
91}
92
93// IsLocked
94bool
95Lockable::IsLocked() const
96{
97	return (fLockOwner == find_thread(NULL));
98}
99
100// QueueLockerCandidate
101void
102Lockable::QueueLockerCandidate(LockerCandidate* candidate)
103{
104	if (!candidate)
105		return;
106	if (fLockOwner >= 0) {
107		fLockerCandidates.Insert(candidate);
108	} else {
109		// if the object is not locked, wake up the candidate right now
110		fLockOwner = candidate->GetThread();
111		fLockCounter = 1;
112		candidate->Unblock(true);
113	}
114}
115