123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- //
- // Basic Threading abstraction (for pthread / win32 based systems)
- //
- // Author: Florian Wilkemeyer <fw@f-ws.de>
- //
- // Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL
- // For more information, see LICENCE in the main folder
- #ifdef WIN32
- #include "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"
- // When Compiling using MSC (on win32..) we know we have support in any case!
- #ifdef _MSC_VER
- #define HAS_TLS
- #endif
- #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
- };
- #ifdef HAS_TLS
- __thread int g_rathread_ID = -1;
- #endif
- ///
- /// 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
- #ifdef HAS_TLS
- g_rathread_ID = 0;
- #endif
- 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.
- #ifdef HAS_TLS
- g_rathread_ID = ((rAthread)p)->myID;
- #endif
- #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( ){
- #ifdef HAS_TLS
- rAthread handle = &l_threads[g_rathread_ID];
-
- if(handle->proc != NULL) // entry point set, so its used!
- return handle;
- #else
- // .. so no tls means we have to search the thread by its api-handle ..
- int i;
- #ifdef WIN32
- HANDLE hSelf;
- hSelf = GetCurrent = GetCurrentThread();
- #else
- pthread_t hSelf;
- hSelf = pthread_self();
- #endif
-
- for(i = 0; i < RA_THREADS_MAX; i++){
- if(l_threads[i].hThread == hSelf && l_threads[i].proc != NULL)
- return &l_threads[i];
- }
-
- #endif
-
- return NULL;
- }//end: rathread_self()
- int rathread_get_tid(){
- #ifdef HAS_TLS
- return g_rathread_ID;
- #else
- // todo
- #ifdef WIN32
- return (int)GetCurrentThreadId();
- #else
- return (intptr_t)pthread_self();
- #endif
-
- #endif
-
- }//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()
|