[16969:16991/trunk/src/] will be re-committed in the next 24 hours. git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@16992 54d463be-8e91-2dee-dedb-b68131a5f0ec
318 lines
6.4 KiB
C
318 lines
6.4 KiB
C
//
|
|
// 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 "../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"
|
|
|
|
// 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()
|