-/* $Id$
-
-This file is part of libmspcore
-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/units.h"
-#include "../time/utils.h"
+#include "systemerror.h"
namespace Msp {
-Semaphore::Semaphore():
- mutex(new Mutex),
- own_mutex(true)
-{
- init();
-}
-
-Semaphore::Semaphore(Mutex &m):
- mutex(&m),
- own_mutex(false)
+struct Semaphore::Private
{
- init();
-}
-
#ifdef WIN32
-int Semaphore::signal()
-{
- if(count==0)
- return 0;
-
- int ret=!ReleaseSemaphore(sem, 1, 0);
-
- unsigned old_count=count;
- mutex->unlock();
- while(count==old_count)
- Sleep(0);
- mutex->lock();
+ HANDLE handle;
+#else
+ Mutex mutex;
+ pthread_cond_t cond;
+ unsigned limit;
+ unsigned count;
+#endif
+};
- return ret;
-}
-int Semaphore::broadcast()
+Semaphore::Semaphore(unsigned limit):
+ priv(new Private)
{
- if(count==0)
- return 0;
- int ret=!ReleaseSemaphore(sem, count, 0);
-
- mutex->unlock();
- while(count)
- Sleep(0);
- mutex->lock();
-
- return ret;
+#ifdef WIN32
+ priv->handle = CreateSemaphore(0, 0, limit, 0);
+#else
+ pthread_cond_init(&priv->cond, 0);
+ priv->limit = limit;
+ priv->count = 0;
+#endif
}
-int Semaphore::wait()
-{
- ++count;
- mutex->unlock();
- DWORD ret=WaitForSingleObject(sem, INFINITE);
- mutex->lock();
- --count;
-
- return ret==WAIT_OBJECT_0;
-}
+Semaphore::~Semaphore()
+{
+#ifdef WIN32
+ CloseHandle(priv->handle);
+#else
+ pthread_cond_destroy(&priv->cond);
#endif
+ delete priv;
+}
-int Semaphore::wait(const Time::TimeDelta &d)
+void Semaphore::signal()
{
-#ifndef WIN32
- Time::TimeStamp ts=Time::now()+d;
-
- timespec timeout;
- timeout.tv_sec=ts.raw()/1000000;
- timeout.tv_nsec=(ts.raw()%1000000)*1000;
-
- int r=pthread_cond_timedwait(&sem, &mutex->mutex, &timeout);
- if(r==ETIMEDOUT)
- return 1;
- else if(r)
- return -1;
- return 0;
+#ifdef WIN32
+ if(!ReleaseSemaphore(priv->handle, 1, 0))
+ throw system_error("Semaphore::signal");
#else
- ++count;
- mutex->lock();
- DWORD ret=WaitForSingleObject(sem, (DWORD)(d/Time::usec));
- mutex->unlock();
- --count;
- return ret==WAIT_OBJECT_0;
+ 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
}
-Semaphore::~Semaphore()
-{
- if(own_mutex)
- delete mutex;
+void Semaphore::wait()
+{
#ifdef WIN32
- CloseHandle(sem);
+ DWORD ret = WaitForSingleObject(priv->handle, INFINITE);
+ if(ret==WAIT_FAILED)
+ throw system_error("Semaphore::wait");
#else
- pthread_cond_destroy(&sem);
+ 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
}
-void Semaphore::init()
+bool Semaphore::wait(const Time::TimeDelta &d)
{
#ifdef WIN32
- count=0;
- sem=CreateSemaphore(0, 0, 32, 0);
+ DWORD ret = WaitForSingleObject(priv->handle, (DWORD)(d/Time::usec));
+ if(ret==WAIT_FAILED)
+ throw system_error("Semaphore::wait");
+ return ret==WAIT_OBJECT_0;
#else
- pthread_cond_init(&sem, 0);
+ 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
}