/Teaching/Operating Systems/Tutorials/SWEB Mutexes
SWEB Mutexes
SWEB Mutexes
have significantly more code than would be necessary. This is bad in terms of readability, but it enhances detection of locking problems.
Maybe the following fully functional Mutex
implementation helps you understanding how a Mutex
works as well as the Mutex
implementation in the SWEB kernel. Here are some functions that can be found in the Mutex.cpp
file:
Mutex::Mutex(const char* name) : mutex_(0), sleepers_(), spinlock_(name) { }
Mutex::~Mutex() { }
bool Mutex::acquireNonBlocking() { spinlock_.acquire(); int old_value = mutex_; mutex_ = 1; spinlock_.release(); return (old_value == 0) ? true : false; // if old_value was 0 we have set it to 1 and therefore acquired the mutex }
void Mutex::acquire() { spinlock_.acquire(); while (mutex_ == 1) { sleepers_.push_back(currentThread); Scheduler::instance()->sleepAndRelease(spinlock_); spinlock_.acquire(); } mutex_ = 1; spinlock_.release(); }
void Mutex::release() { spinlock_.acquire(); mutex_ = 0; Thread* thread = 0; if (!sleepers_.empty()) { thread = sleepers_.front(); sleepers_.pop_front(); } spinlock_.release(); if (thread) Scheduler::instance()->wake(thread); }
Condition Variables
Just in case you are interested, we have a reduced Condition.cpp
too but take this comment in the file seriously (//please note that sleepers list is only protected if lock_ is held!
):
Condition::Condition(Mutex *lock) : sleepers_(), lock_(lock) { }
Condition::~Condition() { }
void Condition::wait() { sleepers_.push_back(currentThread); Scheduler::instance()→sleepAndRelease(*lock_); lock_→acquire(); }
void Condition::waitWithoutReAcquire() { sleepers_.push_back(currentThread); Scheduler::instance()→sleepAndRelease(*lock_); }
void Condition::signal() { if (!sleepers_.empty()) { Thread* thread = sleepers_.front(); Scheduler::instance()→wake(thread); sleepers_.pop_front(); } }
void Condition::broadcast() { ustl::list<Thread*> tmp_threads; while (!sleepers_.empty()) { Thread* thread = sleepers_.front(); sleepers_.pop_front(); Scheduler::instance()→wake(thread); } }