/********************************************************************
 * File: SemaphoreWin32.cpp
 * Author: Keith Schwarz (htiek@cs.stanford.edu)
 *
 * Implementation of the Semaphore class using the Win32 API.
 */
#include "Semaphore.hh"
#include "Monitor.hh"

namespace synch {
  /* Semaphore implementation is just a monitor wrapping the number
   * of permits.
   */
  struct Semaphore::Impl {
    size_t  mPermits;
    Monitor mMonitor;
    
    /* Constructor initializes the number of permits. */
    Impl(size_t permits) : mPermits(permits) {
      // Handled by initializer list
    }
  };
  
  /* Constructor just creates a new Impl. */
  Semaphore::Semaphore(size_t numPermits) : mImpl(new Impl(numPermits)) {
    // Handled by initializer list
  }
  
  /* Destructor cleans up the implementation. */
  Semaphore::~Semaphore() {
    delete mImpl;
  }
  
  /* Nullary lock/unlock forwarded to parameterized lock/unlock. */
  void Semaphore::lock() {
    lock(1);
  }
  void Semaphore::unlock() {
    unlock(1);
  }
  
  /* Parameterized lock waits on the monitor until the proper number of permits
   * are available.
   */
  void Semaphore::lock(size_t numPermits) {
    synchronized (mImpl->mMonitor) {
      /* Wait for the proper number of permits to become available. */
      while (mImpl->mPermits < numPermits)
        mImpl->mMonitor.wait();
      
      /* Grab those permits. */
      mImpl->mPermits -= numPermits;
    }
  }
  
  /* Parameterized lock grabs the monitor, releases the permits, and notifies
   * waiting threads.
   */
  void Semaphore::unlock(size_t numPermits) {
    synchronized (mImpl->mMonitor) {
      mImpl->mPermits += numPermits;
      mImpl->mMonitor.notifyAll();
    }
  }
}
