root/src/add-ons/kernel/file_systems/netfs/server/Lockable.cpp
// 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);
        }
}