-/*
-This file is part of libmspframework
-Copyright © 2006 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
+#ifdef WIN32
+#include <windows.h>
+#else
#include <sys/time.h>
-#include <errno.h>
+#include <cerrno>
+#endif
+#include <msp/time/rawtime_private.h>
+#include <msp/time/timestamp.h>
+#include <msp/time/units.h>
+#include <msp/time/utils.h>
+#include "mutex_private.h"
#include "semaphore.h"
-#include "../time/timestamp.h"
-#include "../time/utils.h"
+#include "systemerror.h"
namespace Msp {
-#ifndef WIN32
-int Semaphore::wait(const Time::TimeDelta &d)
+struct Semaphore::Private
+{
+#ifdef WIN32
+ HANDLE handle;
+#else
+ Mutex mutex;
+ pthread_cond_t cond;
+ unsigned limit;
+ unsigned count;
+#endif
+};
+
+
+Semaphore::Semaphore(unsigned limit):
+ priv(new Private)
{
- Time::TimeStamp ts=Time::now()+d;
-
- timespec timeout;
- timeout.tv_sec=ts.raw()/1000000;
- timeout.tv_nsec=(ts.raw()%1000000)*1000;
-
- MutexLock l(mutex);
- int r=pthread_cond_timedwait(&cond, &mutex.mutex, &timeout);
- if(r==ETIMEDOUT)
- return 1;
- else if(r)
- return -1;
- return 0;
+#ifdef WIN32
+ priv->handle = CreateSemaphore(0, 0, limit, 0);
+#else
+ pthread_cond_init(&priv->cond, 0);
+ priv->limit = limit;
+ priv->count = 0;
+#endif
}
+
+Semaphore::~Semaphore()
+{
+#ifdef WIN32
+ CloseHandle(priv->handle);
+#else
+ pthread_cond_destroy(&priv->cond);
#endif
+ delete priv;
+}
+
+void Semaphore::signal()
+{
+#ifdef WIN32
+ if(!ReleaseSemaphore(priv->handle, 1, 0))
+ throw system_error("Semaphore::signal");
+#else
+ MutexLock mlock(priv->mutex);
+ if(priv->count<priv->limit)
+ ++priv->count;
+ if(int err = pthread_cond_signal(&priv->cond))
+ throw system_error("Semaphore::signal", err);
+#endif
+}
+
+void Semaphore::wait()
+{
+#ifdef WIN32
+ DWORD ret = WaitForSingleObject(priv->handle, INFINITE);
+ if(ret==WAIT_FAILED)
+ throw system_error("Semaphore::wait");
+#else
+ MutexLock mlock(priv->mutex);
+ while(!priv->count)
+ if(int err = pthread_cond_wait(&priv->cond, &priv->mutex.priv->mutex))
+ throw system_error("Semaphore::wait", err);
+ --priv->count;
+#endif
+}
+
+bool Semaphore::wait(const Time::TimeDelta &d)
+{
+#ifdef WIN32
+ DWORD ret = WaitForSingleObject(priv->handle, (DWORD)(d/Time::usec));
+ if(ret==WAIT_FAILED)
+ throw system_error("Semaphore::wait");
+ return ret==WAIT_OBJECT_0;
+#else
+ timespec timeout = Time::rawtime_to_timespec((Time::now()+d).raw());
+
+ int err = pthread_cond_timedwait(&priv->cond, &priv->mutex.priv->mutex, &timeout);
+ if(err && err!=ETIMEDOUT)
+ throw system_error("Semaphore::wait", err);
+ return err==0;
+#endif
+}
} // namespace Msp