123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- // Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL
- // For more information, see LICENCE in the main folder
- #ifdef WIN32
- #include "winapi.hpp"
- #else
- #include <pthread.h>
- #endif
- #include "cbasetypes.h"
- #include "malloc.h"
- #include "showmsg.h"
- #include "timer.h"
- #include "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 );
- InitializeCriticalSection( &c->waiters_lock );
- #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 ] );
- DeleteCriticalSection( &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()
|