viernes, 9 de septiembre de 2011

Implementation of Locks and Condition Variables

Our NachOS distribution:

Previously we stated that we were going to work with NachOS 4.0, and we actually tried to do a lot of things with that distribution, but we couldn't use semaphores or locks on our own code, although they were already implemented, so we tried a different distribution, NachOS 3.4.

In NachOS 3.4, semaphores were already implemented, so we tried to use them right away in our own code.
And surprise, it worked!, we could use them in a little consumer-producer test. So the next thing was to try locks and condition variables. Then we found out that they weren't implemented, just the definition of empty methods. So we decided to try implement it, using NachOS 4.0 as a guide, copy-paste wasn't an option since the 4.0 distribution had different classes to use interrupts, and adding that to NachOS 3.4 was a bit hard.

The changes we made were at the synch.cc and synch.h files as follows(added code is marked in red):

In the synch.cc file:

Lock::Lock(const char* debugName) {
    name = debugName;
    semaphore = new Semaphore("lock", 1);
    lockHolder = NULL;
}

Lock::~Lock() {
    delete semaphore;
}

void Lock::Acquire() {
    semaphore->P();
    lockHolder = currentThread;
}

bool Lock::IsHeldByCurrentThread(){
    return lockHolder == currentThread;
}

void Lock::Release() {
    ASSERT(IsHeldByCurrentThread());
    lockHolder = NULL;
    semaphore->V();
}

Condition::Condition(const char* debugName, Lock* conditionLock) {
    name = debugName;
    waitQueue = new List<Semaphore *>;
}

void Condition::Wait(Lock *conditionLock) {
    Semaphore *waiter;
    ASSERT(conditionLock->IsHeldByCurrentThread());
   
    waiter = new Semaphore("condition", 0);
    waitQueue->Append(waiter);
    conditionLock->Release();
    waiter->P();
    conditionLock->Acquire();
    delete waiter;
 }
void Condition::Signal(Lock *conditionLock) {
    Semaphore *waiter;
    ASSERT(conditionLock->IsHeldByCurrentThread());

    if(!waitQueue->IsEmpty()){
        waiter = waitQueue->Remove();
        waiter->V();
    }
}
void Condition::Broadcast(Lock *conditionLock) {
    while(!waitQueue->IsEmpty()){
        Signal(conditionLock);
    }
}


In the  synch.h file:

class Lock {
  public:
  Lock(const char* debugName);

  ~Lock();          // destructor
  const char* getName() { return name; } 
  void Acquire();
  void Release();
  bool IsHeldByCurrentThread();   

  private:
    const char* name;       
    Thread *lockHolder;
    Semaphore *semaphore;
};

class Condition {
 public:
    Condition(const char* debugName, Lock* conditionLock);   
    ~Condition();   
    const char* getName() { return (name); }
    void Wait(Lock *conditionLock);    
    void Signal(Lock *conditionLock);  
    void Broadcast(Lock *conditionLock);

  private:
    const char* name;
    List<Semaphore *> *waitQueue;
};

Like stated previously, all this changes were made using NachOS 4.0 as a guide, but that distribution used some other class(kernel) to interrupt and do some other stuff, class that is not implemented in 3.4, so we had to work with something else. Using other line codes for example the semaphores, we found out how to manage the interrupts.

That's on locks, now condition variables were easy to implement based on the 4.0 distribution, because it was almost exactly the same code, just adding some missing variables to the synch.h and changing some method names.

The already modified files can be downloaded here:


And that's it. If you have any question, suggestion or anything, feel free to comment.


No hay comentarios:

Publicar un comentario