thread.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. //
  2. // Basic Threading abstraction (for pthread / win32 based systems)
  3. //
  4. // Author: Florian Wilkemeyer <fw@f-ws.de>
  5. //
  6. // Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL
  7. // For more information, see LICENCE in the main folder
  8. #ifdef WIN32
  9. #include "winapi.h"
  10. #define getpagesize() 4096 // @TODO: implement this properly (GetSystemInfo .. dwPageSize..). (Atm as on all supported win platforms its 4k its static.)
  11. #define __thread __declspec( thread )
  12. #else
  13. #include <stdlib.h>
  14. #include <unistd.h>
  15. #include <string.h>
  16. #include <signal.h>
  17. #include <pthread.h>
  18. #include <sched.h>
  19. #endif
  20. #include "cbasetypes.h"
  21. #include "malloc.h"
  22. #include "showmsg.h"
  23. #include "thread.h"
  24. // When Compiling using MSC (on win32..) we know we have support in any case!
  25. #ifdef _MSC_VER
  26. #define HAS_TLS
  27. #endif
  28. #define RA_THREADS_MAX 64
  29. struct rAthread {
  30. unsigned int myID;
  31. RATHREAD_PRIO prio;
  32. rAthreadProc proc;
  33. void *param;
  34. #ifdef WIN32
  35. HANDLE hThread;
  36. #else
  37. pthread_t hThread;
  38. #endif
  39. };
  40. #ifdef HAS_TLS
  41. __thread int g_rathread_ID = -1;
  42. #endif
  43. ///
  44. /// Subystem Code
  45. ///
  46. static struct rAthread l_threads[RA_THREADS_MAX];
  47. void rathread_init(){
  48. register unsigned int i;
  49. memset(&l_threads, 0x00, RA_THREADS_MAX * sizeof(struct rAthread) );
  50. for(i = 0; i < RA_THREADS_MAX; i++){
  51. l_threads[i].myID = i;
  52. }
  53. // now lets init thread id 0, which represnts the main thread
  54. #ifdef HAS_TLS
  55. g_rathread_ID = 0;
  56. #endif
  57. l_threads[0].prio = RAT_PRIO_NORMAL;
  58. l_threads[0].proc = (rAthreadProc)0xDEADCAFE;
  59. }//end: rathread_init()
  60. void rathread_final(){
  61. register unsigned int i;
  62. // Unterminated Threads Left?
  63. // Should'nt happen ..
  64. // Kill 'em all!
  65. //
  66. for(i = 1; i < RA_THREADS_MAX; i++){
  67. if(l_threads[i].proc != NULL){
  68. ShowWarning("rAthread_final: unterminated Thread (tid %u entryPoint %p) - forcing to terminate (kill)\n", i, l_threads[i].proc);
  69. rathread_destroy(&l_threads[i]);
  70. }
  71. }
  72. }//end: rathread_final()
  73. // gets called whenever a thread terminated ..
  74. static void rat_thread_terminated( rAthread handle ){
  75. int id_backup = handle->myID;
  76. // Simply set all members to 0 (except the id)
  77. memset(handle, 0x00, sizeof(struct rAthread));
  78. handle->myID = id_backup; // done ;)
  79. }//end: rat_thread_terminated()
  80. #ifdef WIN32
  81. DWORD WINAPI _raThreadMainRedirector(LPVOID p){
  82. #else
  83. static void *_raThreadMainRedirector( void *p ){
  84. sigset_t set; // on Posix Thread platforms
  85. #endif
  86. void *ret;
  87. // Update myID @ TLS to right id.
  88. #ifdef HAS_TLS
  89. g_rathread_ID = ((rAthread)p)->myID;
  90. #endif
  91. #ifndef WIN32
  92. // When using posix threads
  93. // the threads inherits the Signal mask from the thread which's spawned
  94. // this thread
  95. // so we've to block everything we dont care about.
  96. sigemptyset(&set);
  97. sigaddset(&set, SIGINT);
  98. sigaddset(&set, SIGTERM);
  99. sigaddset(&set, SIGPIPE);
  100. pthread_sigmask(SIG_BLOCK, &set, NULL);
  101. #endif
  102. ret = ((rAthread)p)->proc( ((rAthread)p)->param ) ;
  103. #ifdef WIN32
  104. CloseHandle( ((rAthread)p)->hThread );
  105. #endif
  106. rat_thread_terminated( (rAthread)p );
  107. #ifdef WIN32
  108. return (DWORD)ret;
  109. #else
  110. return ret;
  111. #endif
  112. }//end: _raThreadMainRedirector()
  113. ///
  114. /// API Level
  115. ///
  116. rAthread rathread_create( rAthreadProc entryPoint, void *param ){
  117. return rathread_createEx( entryPoint, param, (1<<23) /*8MB*/, RAT_PRIO_NORMAL );
  118. }//end: rathread_create()
  119. rAthread rathread_createEx( rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio ){
  120. #ifndef WIN32
  121. pthread_attr_t attr;
  122. #endif
  123. size_t tmp;
  124. unsigned int i;
  125. rAthread handle = NULL;
  126. // given stacksize aligned to systems pagesize?
  127. tmp = szStack % getpagesize();
  128. if(tmp != 0)
  129. szStack += tmp;
  130. // Get a free Thread Slot.
  131. for(i = 0; i < RA_THREADS_MAX; i++){
  132. if(l_threads[i].proc == NULL){
  133. handle = &l_threads[i];
  134. break;
  135. }
  136. }
  137. if(handle == NULL){
  138. ShowError("rAthread: cannot create new thread (entryPoint: %p) - no free thread slot found!", entryPoint);
  139. return NULL;
  140. }
  141. handle->proc = entryPoint;
  142. handle->param = param;
  143. #ifdef WIN32
  144. handle->hThread = CreateThread(NULL, szStack, _raThreadMainRedirector, (void*)handle, 0, NULL);
  145. #else
  146. pthread_attr_init(&attr);
  147. pthread_attr_setstacksize(&attr, szStack);
  148. if(pthread_create(&handle->hThread, &attr, _raThreadMainRedirector, (void*)handle) != 0){
  149. handle->proc = NULL;
  150. handle->param = NULL;
  151. return NULL;
  152. }
  153. pthread_attr_destroy(&attr);
  154. #endif
  155. rathread_prio_set( handle, prio );
  156. return handle;
  157. }//end: rathread_createEx
  158. void rathread_destroy ( rAthread handle ){
  159. #ifdef WIN32
  160. if( TerminateThread(handle->hThread, 0) != FALSE){
  161. CloseHandle(handle->hThread);
  162. rat_thread_terminated(handle);
  163. }
  164. #else
  165. if( pthread_cancel( handle->hThread ) == 0){
  166. // We have to join it, otherwise pthread wont re-cycle its internal ressources assoc. with this thread.
  167. //
  168. pthread_join( handle->hThread, NULL );
  169. // Tell our manager to release ressources ;)
  170. rat_thread_terminated(handle);
  171. }
  172. #endif
  173. }//end: rathread_destroy()
  174. rAthread rathread_self( ){
  175. #ifdef HAS_TLS
  176. rAthread handle = &l_threads[g_rathread_ID];
  177. if(handle->proc != NULL) // entry point set, so its used!
  178. return handle;
  179. #else
  180. // .. so no tls means we have to search the thread by its api-handle ..
  181. int i;
  182. #ifdef WIN32
  183. HANDLE hSelf;
  184. hSelf = GetCurrent = GetCurrentThread();
  185. #else
  186. pthread_t hSelf;
  187. hSelf = pthread_self();
  188. #endif
  189. for(i = 0; i < RA_THREADS_MAX; i++){
  190. if(l_threads[i].hThread == hSelf && l_threads[i].proc != NULL)
  191. return &l_threads[i];
  192. }
  193. #endif
  194. return NULL;
  195. }//end: rathread_self()
  196. int rathread_get_tid(){
  197. #ifdef HAS_TLS
  198. return g_rathread_ID;
  199. #else
  200. // todo
  201. #ifdef WIN32
  202. return (int)GetCurrentThreadId();
  203. #else
  204. return (intptr_t)pthread_self();
  205. #endif
  206. #endif
  207. }//end: rathread_get_tid()
  208. bool rathread_wait( rAthread handle, void* *out_exitCode ){
  209. // Hint:
  210. // no thread data cleanup routine call here!
  211. // its managed by the callProxy itself..
  212. //
  213. #ifdef WIN32
  214. WaitForSingleObject(handle->hThread, INFINITE);
  215. return true;
  216. #else
  217. if(pthread_join(handle->hThread, out_exitCode) == 0)
  218. return true;
  219. return false;
  220. #endif
  221. }//end: rathread_wait()
  222. void rathread_prio_set( rAthread handle, RATHREAD_PRIO prio ){
  223. handle->prio = RAT_PRIO_NORMAL;
  224. //@TODO
  225. }//end: rathread_prio_set()
  226. RATHREAD_PRIO rathread_prio_get( rAthread handle){
  227. return handle->prio;
  228. }//end: rathread_prio_get()
  229. void rathread_yield(){
  230. #ifdef WIN32
  231. SwitchToThread();
  232. #else
  233. sched_yield();
  234. #endif
  235. }//end: rathread_yield()