Browse Source

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://svn.code.sf.net/p/rathena/svn/trunk@16256 54d463be-8e91-2dee-dedb-b68131a5f0ec

blacksirius 13 years ago
parent
commit
12b9fdab9c
4 changed files with 358 additions and 1 deletions
  1. 1 1
      src/common/Makefile.in
  2. 24 0
      src/common/cbasetypes.h
  3. 244 0
      src/common/mutex.c
  4. 89 0
      src/common/mutex.h

+ 1 - 1
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)
 

+ 24 - 0
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
 //////////////////////////////////////////////////////////////////////////

+ 244 - 0
src/common/mutex.c

@@ -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()
+
+

+ 89 - 0
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