xref: /haiku/src/add-ons/kernel/file_systems/netfs/server/Lockable.cpp (revision 5a1d355fdf2747f80f8c46e2539f844a0b813346)
1 // Lockable.cpp
2 
3 #include "Lockable.h"
4 
5 
6 // LockerCandidate
7 
8 // constructor
LockerCandidate(Blocker blocker)9 LockerCandidate::LockerCandidate(Blocker blocker)
10 	: fBlocker(blocker),
11 	  fThread(find_thread(NULL))
12 {
13 }
14 
15 // GetThread
16 thread_id
GetThread() const17 LockerCandidate::GetThread() const
18 {
19 	return fThread;
20 }
21 
22 // Block
23 status_t
Block()24 LockerCandidate::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
35 status_t
Unblock(bool success)36 LockerCandidate::Unblock(bool success)
37 {
38 	return fBlocker.Unblock(success);
39 }
40 
41 
42 // #pragma mark -
43 
44 // Lockable
45 
46 // constructor
Lockable()47 Lockable::Lockable()
48 	: fLockOwner(-1),
49 	  fLockCounter(0)
50 {
51 }
52 
53 // destructor
~Lockable()54 Lockable::~Lockable()
55 {
56 	// unblock all
57 	while (LockerCandidate* candidate = fLockerCandidates.First()) {
58 		fLockerCandidates.Remove(candidate);
59 		candidate->Unblock(false);
60 	}
61 }
62 
63 // Lock
64 bool
Lock()65 Lockable::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
76 void
Unlock()77 Lockable::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
94 bool
IsLocked() const95 Lockable::IsLocked() const
96 {
97 	return (fLockOwner == find_thread(NULL));
98 }
99 
100 // QueueLockerCandidate
101 void
QueueLockerCandidate(LockerCandidate * candidate)102 Lockable::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