diff options
author | blacksirius <blacksirius@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2012-06-03 18:53:02 +0000 |
---|---|---|
committer | blacksirius <blacksirius@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2012-06-03 18:53:02 +0000 |
commit | 4feeab8c61334ec73172fa01cda951dafde2505f (patch) | |
tree | 078521eec3b26bd7fcfd42c9d1615d35be6b3ec9 /src/common/thread.c | |
parent | 40ede8fd21bdb39c01665c90aa420a03a712c96c (diff) | |
download | hercules-4feeab8c61334ec73172fa01cda951dafde2505f.tar.gz hercules-4feeab8c61334ec73172fa01cda951dafde2505f.tar.bz2 hercules-4feeab8c61334ec73172fa01cda951dafde2505f.tar.xz hercules-4feeab8c61334ec73172fa01cda951dafde2505f.zip |
feature merge bs-coreoptimize->trunk: Atomic Operations, Threading, Spinlock implemnetation. [commit 1/2, windows will followup]
- Added Abstractions for Atomic Operations (lock instructions.. windows guy's may now this as Interlocked* stuff ..)
- Added Threading api abstraction for Pthread based OS's and Windows
- Added Spinlock Implementation (uses CAS / if you need more informations - just read the source - its simple.)
- Due to Interlocked(Compare)Exchange64 .. we now require at least i686 (Pentium Pro) for 32Bit Builds :)
youll also may feel some performance improvements when using 32bit builsd due to "newer" minimal arch
the compiler is now able to use CMOV's ....
================================================================
= Important Warning:
================================================================
Dont use threading at the moment athena is not threadsafe!
you'll mess up everthing when accessing data from other threads .., no synchronization is provided.
A way to process tasks asynchronously will come up after / with the new socket system.
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@16221 54d463be-8e91-2dee-dedb-b68131a5f0ec
Diffstat (limited to 'src/common/thread.c')
-rw-r--r-- | src/common/thread.c | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/src/common/thread.c b/src/common/thread.c new file mode 100644 index 000000000..49accff4c --- /dev/null +++ b/src/common/thread.c @@ -0,0 +1,270 @@ + +#ifdef WIN32 +#include "../common/winapi.h" +#define getpagesize() 4096 // @TODO: implement this properly (GetSystemInfo .. dwPageSize..). (Atm as on all supported win platforms its 4k its static.) +#define __thread __declspec( thread ) +#else +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <pthread.h> +#include <sched.h> +#endif + +#include "cbasetypes.h" +#include "malloc.h" +#include "showmsg.h" +#include "thread.h" + + +#define RA_THREADS_MAX 64 + +struct rAthread { + unsigned int myID; + + RATHREAD_PRIO prio; + rAthreadProc proc; + void *param; + + #ifdef WIN32 + HANDLE hThread; + #else + pthread_t hThread; + #endif +}; + + +__thread int g_rathread_ID = -1; + + +/// +/// Subystem Code +/// +static struct rAthread l_threads[RA_THREADS_MAX]; + +void rathread_init(){ + register unsigned int i; + memset(&l_threads, 0x00, RA_THREADS_MAX * sizeof(struct rAthread) ); + + for(i = 0; i < RA_THREADS_MAX; i++){ + l_threads[i].myID = i; + } + + // now lets init thread id 0, which represnts the main thread + g_rathread_ID = 0; + l_threads[0].prio = RAT_PRIO_NORMAL; + l_threads[0].proc = (rAthreadProc)0xDEADCAFE; + +}//end: rathread_init() + + + +void rathread_final(){ + register unsigned int i; + + // Unterminated Threads Left? + // Should'nt happen .. + // Kill 'em all! + // + for(i = 1; i < RA_THREADS_MAX; i++){ + if(l_threads[i].proc != NULL){ + ShowWarning("rAthread_final: unterminated Thread (tid %u entryPoint %p) - forcing to terminate (kill)\n", i, l_threads[i].proc); + rathread_destroy(&l_threads[i]); + } + } + + +}//end: rathread_final() + + + +// gets called whenever a thread terminated .. +static void rat_thread_terminated( rAthread handle ){ + + int id_backup = handle->myID; + + // Simply set all members to 0 (except the id) + memset(handle, 0x00, sizeof(struct rAthread)); + + handle->myID = id_backup; // done ;) + +}//end: rat_thread_terminated() + +#ifdef WIN32 +DWORD WINAPI _raThreadMainRedirector(LPVOID p){ +#else +static void *_raThreadMainRedirector( void *p ){ + sigset_t set; // on Posix Thread platforms +#endif + void *ret; + + // Update myID @ TLS to right id. + g_rathread_ID = ((rAthread)p)->myID; + +#ifndef WIN32 + // When using posix threads + // the threads inherits the Signal mask from the thread which's spawned + // this thread + // so we've to block everything we dont care about. + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGTERM); + sigaddset(&set, SIGPIPE); + + pthread_sigmask(SIG_BLOCK, &set, NULL); + +#endif + + + ret = ((rAthread)p)->proc( ((rAthread)p)->param ) ; + +#ifdef WIN32 + CloseHandle( ((rAthread)p)->hThread ); +#endif + + rat_thread_terminated( (rAthread)p ); +#ifdef WIN32 + return (DWORD)ret; +#else + return ret; +#endif +}//end: _raThreadMainRedirector() + + + + + +/// +/// API Level +/// +rAthread rathread_create( rAthreadProc entryPoint, void *param ){ + return rathread_createEx( entryPoint, param, (1<<23) /*8MB*/, RAT_PRIO_NORMAL ); +}//end: rathread_create() + + +rAthread rathread_createEx( rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio ){ +#ifndef WIN32 + pthread_attr_t attr; +#endif + size_t tmp; + unsigned int i; + rAthread handle = NULL; + + + // given stacksize aligned to systems pagesize? + tmp = szStack % getpagesize(); + if(tmp != 0) + szStack += tmp; + + + // Get a free Thread Slot. + for(i = 0; i < RA_THREADS_MAX; i++){ + if(l_threads[i].proc == NULL){ + handle = &l_threads[i]; + break; + } + } + + if(handle == NULL){ + ShowError("rAthread: cannot create new thread (entryPoint: %p) - no free thread slot found!", entryPoint); + return NULL; + } + + + + handle->proc = entryPoint; + handle->param = param; + +#ifdef WIN32 + handle->hThread = CreateThread(NULL, szStack, _raThreadMainRedirector, (void*)handle, 0, NULL); +#else + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, szStack); + + if(pthread_create(&handle->hThread, &attr, _raThreadMainRedirector, (void*)handle) != 0){ + handle->proc = NULL; + handle->param = NULL; + return NULL; + } + pthread_attr_destroy(&attr); +#endif + + rathread_prio_set( handle, prio ); + + return handle; +}//end: rathread_createEx + + +void rathread_destroy ( rAthread handle ){ +#ifdef WIN32 + if( TerminateThread(handle->hThread, 0) != FALSE){ + CloseHandle(handle->hThread); + rat_thread_terminated(handle); + } +#else + if( pthread_cancel( handle->hThread ) == 0){ + + // We have to join it, otherwise pthread wont re-cycle its internal ressources assoc. with this thread. + // + pthread_join( handle->hThread, NULL ); + + // Tell our manager to release ressources ;) + rat_thread_terminated(handle); + } +#endif +}//end: rathread_destroy() + +rAthread rathread_self( ){ + rAthread handle = &l_threads[g_rathread_ID]; + + if(handle->proc != NULL) // entry point set, so its used! + return handle; + + return NULL; +}//end: rathread_self() + + +int rathread_get_tid(){ + + return g_rathread_ID; + +}//end: rathread_get_tid() + + +bool rathread_wait( rAthread handle, void* *out_exitCode ){ + + // Hint: + // no thread data cleanup routine call here! + // its managed by the callProxy itself.. + // +#ifdef WIN32 + WaitForSingleObject(handle->hThread, INFINITE); + return true; +#else + if(pthread_join(handle->hThread, out_exitCode) == 0) + return true; + return false; +#endif + +}//end: rathread_wait() + + +void rathread_prio_set( rAthread handle, RATHREAD_PRIO prio ){ + handle->prio = RAT_PRIO_NORMAL; + //@TODO +}//end: rathread_prio_set() + + +RATHREAD_PRIO rathread_prio_get( rAthread handle){ + return handle->prio; +}//end: rathread_prio_get() + + +void rathread_yield(){ +#ifdef WIN32 + SwitchToThread(); +#else + sched_yield(); +#endif +}//end: rathread_yield() |