summaryrefslogtreecommitdiff
path: root/src/common/thread.c
diff options
context:
space:
mode:
authorblacksirius <blacksirius@54d463be-8e91-2dee-dedb-b68131a5f0ec>2012-06-03 18:53:02 +0000
committerblacksirius <blacksirius@54d463be-8e91-2dee-dedb-b68131a5f0ec>2012-06-03 18:53:02 +0000
commit4feeab8c61334ec73172fa01cda951dafde2505f (patch)
tree078521eec3b26bd7fcfd42c9d1615d35be6b3ec9 /src/common/thread.c
parent40ede8fd21bdb39c01665c90aa420a03a712c96c (diff)
downloadhercules-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.c270
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()