⛏️ index : haiku.git

// Lockable.cpp

#include "Lockable.h"


// LockerCandidate

// constructor
LockerCandidate::LockerCandidate(Blocker blocker)
	: fBlocker(blocker),
	  fThread(find_thread(NULL))
{
}

// GetThread
thread_id
LockerCandidate::GetThread() const
{
	return fThread;
}

// Block
status_t
LockerCandidate::Block()
{
	int32 userData;
	status_t error = fBlocker.Block(&userData);
	if (error != B_OK)
		return error;

	return (userData ? B_OK : B_ENTRY_NOT_FOUND);
}

// Unblock
status_t
LockerCandidate::Unblock(bool success)
{
	return fBlocker.Unblock(success);
}


// #pragma mark -

// Lockable

// constructor
Lockable::Lockable()
	: fLockOwner(-1),
	  fLockCounter(0)
{
}

// destructor
Lockable::~Lockable()
{
	// unblock all
	while (LockerCandidate* candidate = fLockerCandidates.First()) {
		fLockerCandidates.Remove(candidate);
		candidate->Unblock(false);
	}
}

// Lock
bool
Lockable::Lock()
{
	thread_id thread = find_thread(NULL);
	if (fLockOwner >= 0 && fLockOwner != thread)
		return false;
	fLockOwner = thread;
	fLockCounter++;
	return true;
}

// Unlock
void
Lockable::Unlock()
{
	thread_id thread = find_thread(NULL);
	if (fLockOwner != thread)
		return;
	if (--fLockCounter > 0)
		return;
	if (LockerCandidate* candidate = fLockerCandidates.First()) {
		fLockerCandidates.Remove(candidate);
		fLockOwner = candidate->GetThread();
		fLockCounter = 1;
		candidate->Unblock(true);
	} else
		fLockOwner = -1;
}

// IsLocked
bool
Lockable::IsLocked() const
{
	return (fLockOwner == find_thread(NULL));
}

// QueueLockerCandidate
void
Lockable::QueueLockerCandidate(LockerCandidate* candidate)
{
	if (!candidate)
		return;
	if (fLockOwner >= 0) {
		fLockerCandidates.Insert(candidate);
	} else {
		// if the object is not locked, wake up the candidate right now
		fLockOwner = candidate->GetThread();
		fLockCounter = 1;
		candidate->Unblock(true);
	}
}