/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.cppfile:

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); 
  } 
}