From caa66e7c20a26859912c1efc3c5a00b8dafc0661 Mon Sep 17 00:00:00 2001 From: blacksirius Date: Sun, 10 Jun 2012 02:27:07 +0000 Subject: added mutex && cond var abstraction ( for pthread / winapi ) added type 'sysint' to cbasetypes, which's the width of the platform the release gets compiled for. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@16256 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/common/Makefile.in | 2 +- src/common/cbasetypes.h | 24 +++++ src/common/mutex.c | 244 ++++++++++++++++++++++++++++++++++++++++++++++++ src/common/mutex.h | 89 ++++++++++++++++++ 4 files changed, 358 insertions(+), 1 deletion(-) create mode 100644 src/common/mutex.c create mode 100644 src/common/mutex.h diff --git a/src/common/Makefile.in b/src/common/Makefile.in index 9b2ffdd39..3f03982d7 100644 --- a/src/common/Makefile.in +++ b/src/common/Makefile.in @@ -3,7 +3,7 @@ COMMON_OBJ = obj_all/core.o obj_all/socket.o obj_all/timer.o obj_all/db.o obj_al obj_all/nullpo.o obj_all/malloc.o obj_all/showmsg.o obj_all/strlib.o obj_all/utils.o \ obj_all/grfio.o obj_all/mapindex.o obj_all/ers.o obj_all/md5calc.o \ obj_all/minicore.o obj_all/minisocket.o obj_all/minimalloc.o obj_all/random.o obj_all/des.o \ - obj_all/conf.o obj_all/thread.o + obj_all/conf.o obj_all/thread.o obj_all/mutex.o COMMON_H = $(shell ls ../common/*.h) diff --git a/src/common/cbasetypes.h b/src/common/cbasetypes.h index 5ed4a3974..62cb8fe21 100644 --- a/src/common/cbasetypes.h +++ b/src/common/cbasetypes.h @@ -197,6 +197,30 @@ typedef intptr_t intptr; typedef uintptr_t uintptr; +////////////////////////////////////////////////////////////////////////// +// Add a 'sysint' Type which has the width of the platform we're compiled for. +////////////////////////////////////////////////////////////////////////// +#if defined(__GNUC__) + #if defined(__x86_64__) + typedef int64 sysint; + typedef uint64 usysint; + #else + typedef int32 sysint; + typedef uint32 usysint; + #endif +#elif defined(_MSC_VER) + #if defined(_M_X64) + typedef int64 sysint; + typedef uint64 usysint; + #else + typedef int32 sysint; + typedef uint32 usysint; + #endif +#else + #error Compiler / Platform is unsupported. +#endif + + ////////////////////////////////////////////////////////////////////////// // some redefine of function redefines for some Compilers ////////////////////////////////////////////////////////////////////////// diff --git a/src/common/mutex.c b/src/common/mutex.c new file mode 100644 index 000000000..874b81fa2 --- /dev/null +++ b/src/common/mutex.c @@ -0,0 +1,244 @@ + +#ifdef WIN32 +#include "../common/winapi.h" +#else +#include +#include +#include +#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() + + diff --git a/src/common/mutex.h b/src/common/mutex.h new file mode 100644 index 000000000..4a32bcc8a --- /dev/null +++ b/src/common/mutex.h @@ -0,0 +1,89 @@ +#ifndef _rA_MUTEX_H_ +#define _rA_MUTEX_H_ + + +typedef struct ramutex *ramutex; // Mutex +typedef struct racond *racond; // Condition Var + +/** + * Creates a Mutex + * + * @return not NULL + */ +ramutex ramutex_create(); + +/** + * Destroys a Mutex + * + * @param m - the mutex to destroy + */ +void ramutex_destroy( ramutex m ); + +/** + * Gets a lock + * + * @param m - the mutex to lock + */ +void ramutex_lock( ramutex m); + +/** + * Trys to get the Lock + * + * @param m - the mutex try to lock + * + * @return boolean (true = got the lock) + */ +bool ramutex_trylock( ramutex m ); + +/** + * Unlocks a mutex + * + * @param m - the mutex to unlock + */ +void ramutex_unlock( ramutex m); + + +/** + * Creates a Condition variable + * + * @return not NULL + */ +racond racond_create(); + +/** + * Destroy a Condition variable + * + * @param c - the condition varaible to destroy + */ +void racond_destroy( racond c ); + +/** + * Waits Until state is signalled + * + * @param c - the condition var to wait for signalled state + * @param m - the mutex used for syncronization + * @param timeout_ticks - timeout in ticks ( -1 = INFINITE ) + */ +void racond_wait( racond c, ramutex m, sysint timeout_ticks); + +/** + * Sets the given condition var to signalled state + * + * @param c - condition var to set in signalled state. + * + * @note: + * Only one waiter gets notified. + */ +void racond_signal( racond c ); + +/** + * Sets notifys all waiting threads thats signalled. + * @param c - condition var to set in signalled state + * + * @note: + * All Waiters getting notified. + */ +void racond_broadcast( racond c ); + + +#endif -- cgit v1.2.3-60-g2f50