|
@@ -0,0 +1,244 @@
|
|
|
|
+
|
|
|
|
+#ifdef WIN32
|
|
|
|
+#include "../common/winapi.h"
|
|
|
|
+#else
|
|
|
|
+#include <pthread.h>
|
|
|
|
+#include <time.h>
|
|
|
|
+#include <sys/time.h>
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+#include "../common/cbasetypes.h"
|
|
|
|
+#include "../common/malloc.h"
|
|
|
|
+#include "../common/showmsg.h"
|
|
|
|
+#include "../common/timer.h"
|
|
|
|
+#include "../common/mutex.h"
|
|
|
|
+
|
|
|
|
+struct ramutex{
|
|
|
|
+#ifdef WIN32
|
|
|
|
+ CRITICAL_SECTION hMutex;
|
|
|
|
+#else
|
|
|
|
+ pthread_mutex_t hMutex;
|
|
|
|
+#endif
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+struct racond{
|
|
|
|
+#ifdef WIN32
|
|
|
|
+ HANDLE events[2];
|
|
|
|
+ ra_align(8) volatile LONG nWaiters;
|
|
|
|
+ CRITICAL_SECTION waiters_lock;
|
|
|
|
+
|
|
|
|
+#define EVENT_COND_SIGNAL 0
|
|
|
|
+#define EVENT_COND_BROADCAST 1
|
|
|
|
+
|
|
|
|
+#else
|
|
|
|
+ pthread_cond_t hCond;
|
|
|
|
+#endif
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+////////////////////
|
|
|
|
+// Mutex
|
|
|
|
+//
|
|
|
|
+// Implementation:
|
|
|
|
+//
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ramutex ramutex_create(){
|
|
|
|
+ struct ramutex *m;
|
|
|
|
+
|
|
|
|
+ m = (struct ramutex*)aMalloc( sizeof(struct ramutex) );
|
|
|
|
+ if(m == NULL){
|
|
|
|
+ ShowFatalError("ramutex_create: OOM while allocating %u bytes.\n", sizeof(struct ramutex));
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+#ifdef WIN32
|
|
|
|
+ InitializeCriticalSection(&m->hMutex);
|
|
|
|
+#else
|
|
|
|
+ pthread_mutex_init(&m->hMutex, NULL);
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ return m;
|
|
|
|
+}//end: ramutex_create()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+void ramutex_destroy( ramutex m ){
|
|
|
|
+
|
|
|
|
+#ifdef WIN32
|
|
|
|
+ DeleteCriticalSection(&m->hMutex);
|
|
|
|
+#else
|
|
|
|
+ pthread_mutex_destroy(&m->hMutex);
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ aFree(m);
|
|
|
|
+
|
|
|
|
+}//end: ramutex_destroy()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+void ramutex_lock( ramutex m ){
|
|
|
|
+
|
|
|
|
+#ifdef WIN32
|
|
|
|
+ EnterCriticalSection(&m->hMutex);
|
|
|
|
+#else
|
|
|
|
+ pthread_mutex_lock(&m->hMutex);
|
|
|
|
+#endif
|
|
|
|
+}//end: ramutex_lock
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+bool ramutex_trylock( ramutex m ){
|
|
|
|
+#ifdef WIN32
|
|
|
|
+ if(TryEnterCriticalSection(&m->hMutex) == TRUE)
|
|
|
|
+ return true;
|
|
|
|
+
|
|
|
|
+ return false;
|
|
|
|
+#else
|
|
|
|
+ if(pthread_mutex_trylock(&m->hMutex) == 0)
|
|
|
|
+ return true;
|
|
|
|
+
|
|
|
|
+ return false;
|
|
|
|
+#endif
|
|
|
|
+}//end: ramutex_trylock()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+void ramutex_unlock( ramutex m ){
|
|
|
|
+#ifdef WIN32
|
|
|
|
+ LeaveCriticalSection(&m->hMutex);
|
|
|
|
+#else
|
|
|
|
+ pthread_mutex_unlock(&m->hMutex);
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+}//end: ramutex_unlock()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+///////////////
|
|
|
|
+// Condition Variables
|
|
|
|
+//
|
|
|
|
+// Implementation:
|
|
|
|
+//
|
|
|
|
+
|
|
|
|
+racond racond_create(){
|
|
|
|
+ struct racond *c;
|
|
|
|
+
|
|
|
|
+ c = (struct racond*)aMalloc( sizeof(struct racond) );
|
|
|
|
+ if(c == NULL){
|
|
|
|
+ ShowFatalError("racond_create: OOM while allocating %u bytes\n", sizeof(struct racond));
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+#ifdef WIN32
|
|
|
|
+ c->nWaiters = 0;
|
|
|
|
+ c->events[ EVENT_COND_SIGNAL ] = CreateEvent( NULL, FALSE, FALSE, NULL );
|
|
|
|
+ c->events[ EVENT_COND_BROADCAST ] = CreateEvent( NULL, TRUE, FALSE, NULL );
|
|
|
|
+#else
|
|
|
|
+ pthread_cond_init(&c->hCond, NULL);
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ return c;
|
|
|
|
+}//end: racond_create()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+void racond_destroy( racond c ){
|
|
|
|
+#ifdef WIN32
|
|
|
|
+ CloseHandle( c->events[ EVENT_COND_SIGNAL ] );
|
|
|
|
+ CloseHandle( c->events[ EVENT_COND_BROADCAST ] );
|
|
|
|
+ InitializeCriticalSection( &c->waiters_lock );
|
|
|
|
+#else
|
|
|
|
+ pthread_cond_destroy(&c->hCond);
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ aFree(c);
|
|
|
|
+}//end: racond_destroy()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+void racond_wait( racond c, ramutex m, sysint timeout_ticks){
|
|
|
|
+#ifdef WIN32
|
|
|
|
+ register DWORD ms;
|
|
|
|
+ int result;
|
|
|
|
+ bool is_last = false;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ EnterCriticalSection(&c->waiters_lock);
|
|
|
|
+ c->nWaiters++;
|
|
|
|
+ LeaveCriticalSection(&c->waiters_lock);
|
|
|
|
+
|
|
|
|
+ if(timeout_ticks < 0)
|
|
|
|
+ ms = INFINITE;
|
|
|
|
+ else
|
|
|
|
+ ms = (timeout_ticks > MAXDWORD) ? (MAXDWORD - 1) : (DWORD)timeout_ticks;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ // we can release the mutex (m) here, cause win's
|
|
|
|
+ // manual reset events maintain state when used with
|
|
|
|
+ // SetEvent()
|
|
|
|
+ ramutex_unlock(m);
|
|
|
|
+
|
|
|
|
+ result = WaitForMultipleObjects(2, c->events, FALSE, ms);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ EnterCriticalSection(&c->waiters_lock);
|
|
|
|
+ c->nWaiters--;
|
|
|
|
+ if( (result == WAIT_OBJECT_0 + EVENT_COND_BROADCAST) && (c->nWaiters == 0) )
|
|
|
|
+ is_last = true; // Broadcast called!
|
|
|
|
+ LeaveCriticalSection(&c->waiters_lock);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ // we are the last waiter that has to be notified, or to stop waiting
|
|
|
|
+ // so we have to do a manual reset
|
|
|
|
+ if(is_last == true)
|
|
|
|
+ ResetEvent( c->events[EVENT_COND_BROADCAST] );
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ ramutex_lock(m);
|
|
|
|
+
|
|
|
|
+#else
|
|
|
|
+ if(timeout_ticks < 0){
|
|
|
|
+ pthread_cond_wait( &c->hCond, &m->hMutex );
|
|
|
|
+ }else{
|
|
|
|
+ struct timespec wtime;
|
|
|
|
+ int64 exact_timeout = gettick() + timeout_ticks;
|
|
|
|
+
|
|
|
|
+ wtime.tv_sec = exact_timeout/1000;
|
|
|
|
+ wtime.tv_nsec = (exact_timeout%1000)*1000000;
|
|
|
|
+
|
|
|
|
+ pthread_cond_timedwait( &c->hCond, &m->hMutex, &wtime);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+#endif
|
|
|
|
+}//end: racond_wait()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+void racond_signal( racond c ){
|
|
|
|
+#ifdef WIN32
|
|
|
|
+// bool has_waiters = false;
|
|
|
|
+// EnterCriticalSection(&c->waiters_lock);
|
|
|
|
+// if(c->nWaiters > 0)
|
|
|
|
+// has_waiters = true;
|
|
|
|
+// LeaveCriticalSection(&c->waiters_lock);
|
|
|
|
+
|
|
|
|
+// if(has_waiters == true)
|
|
|
|
+ SetEvent( c->events[ EVENT_COND_SIGNAL ] );
|
|
|
|
+#else
|
|
|
|
+ pthread_cond_signal(&c->hCond);
|
|
|
|
+#endif
|
|
|
|
+}//end: racond_signal()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+void racond_broadcast( racond c ){
|
|
|
|
+#ifdef WIN32
|
|
|
|
+// bool has_waiters = false;
|
|
|
|
+// EnterCriticalSection(&c->waiters_lock);
|
|
|
|
+// if(c->nWaiters > 0)
|
|
|
|
+// has_waiters = true;
|
|
|
|
+// LeaveCriticalSection(&c->waiters_lock);
|
|
|
|
+
|
|
|
|
+// if(has_waiters == true)
|
|
|
|
+ SetEvent( c->events[ EVENT_COND_BROADCAST ] );
|
|
|
|
+#else
|
|
|
|
+ pthread_cond_broadcast(&c->hCond);
|
|
|
|
+#endif
|
|
|
|
+}//end: racond_broadcast()
|
|
|
|
+
|
|
|
|
+
|