]> git.tdb.fi Git - libs/core.git/blobdiff - source/core/semaphore.cpp
Use the system call name as parameter to system_error
[libs/core.git] / source / core / semaphore.cpp
index 139cae2f4ca523ffac47af9487663799a65c17ea..06e8435c3a34212599a8ead8817d28073c4c26cc 100644 (file)
-/* $Id$
-
-This file is part of libmspcore
-Copyright © 2006  Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#ifndef WIN32
+#ifdef WIN32
+#include <windows.h>
+#else
 #include <sys/time.h>
+#include <cerrno>
 #endif
-#include <errno.h>
+#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)
+struct Semaphore::Private
 {
-       init();
-}
+#ifdef WIN32
+       HANDLE handle;
+#else
+       Mutex mutex;
+       pthread_cond_t cond;
+       unsigned limit;
+       unsigned count;
+#endif
+};
 
-Semaphore::Semaphore(Mutex &m):
-       mutex(&m),
-       own_mutex(false)
-{
-       init();
-}
 
-void Semaphore::init()
+Semaphore::Semaphore(unsigned limit):
+       priv(new Private)
 {
 #ifdef WIN32
-       count = 0;
-       sem = CreateSemaphore(0, 0, 32, 0);
+       priv->handle = CreateSemaphore(0, 0, limit, 0);
 #else
-       pthread_cond_init(&sem, 0);
+       pthread_cond_init(&priv->cond, 0);
+       priv->limit = limit;
+       priv->count = 0;
 #endif
 }
 
 Semaphore::~Semaphore()
 {
-       if(own_mutex)
-               delete mutex;
 #ifdef WIN32
-       CloseHandle(sem);
+       CloseHandle(priv->handle);
 #else
-       pthread_cond_destroy(&sem);
+       pthread_cond_destroy(&priv->cond);
 #endif
+       delete priv;
 }
 
-#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();
-
-       return ret;
-}
-
-int Semaphore::broadcast()
+void Semaphore::signal()
 {
-       if(count==0)
-               return 0;
-       int ret = !ReleaseSemaphore(sem, count, 0);
-
-       mutex->unlock();
-       while(count)
-               Sleep(0);
-       mutex->lock();
-
-       return ret;
+#ifdef WIN32
+       if(!ReleaseSemaphore(priv->handle, 1, 0))
+               throw system_error("ReleaseSemaphore");
+#else
+       MutexLock mlock(priv->mutex);
+       if(priv->count<priv->limit)
+               ++priv->count;
+       if(int err = pthread_cond_signal(&priv->cond))
+               throw system_error("pthread_cond_signal", err);
+#endif
 }
 
-int Semaphore::wait()
+void Semaphore::wait()
 { 
-       ++count; 
-       mutex->unlock();
-       DWORD ret = WaitForSingleObject(sem, INFINITE); 
-       mutex->lock();
-       --count;
-       
-       return ret==WAIT_OBJECT_0;
-}
+#ifdef WIN32
+       DWORD ret = WaitForSingleObject(priv->handle, INFINITE);
+       if(ret==WAIT_FAILED)
+               throw system_error("WaitForSingleObject");
+#else
+       MutexLock mlock(priv->mutex);
+       while(!priv->count)
+               if(int err = pthread_cond_wait(&priv->cond, &priv->mutex.priv->mutex))
+                       throw system_error("pthread_cond_wait", err);
+       --priv->count;
 #endif
+}
 
-int Semaphore::wait(const Time::TimeDelta &d)
+bool Semaphore::wait(const Time::TimeDelta &d)
 {
-#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;
-#else
-       ++count;
-       mutex->lock();
-       DWORD ret = WaitForSingleObject(sem, (DWORD)(d/Time::usec));
-       mutex->unlock();
-       --count;
+#ifdef WIN32
+       DWORD ret = WaitForSingleObject(priv->handle, (DWORD)(d/Time::usec));
+       if(ret==WAIT_FAILED)
+               throw system_error("WaitForSingleObject");
        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("pthread_cond_timedwait", err);
+       return err==0;
 #endif
 }