blitz_thread.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. #include "blitz.h"
  2. #include "bdwgc/libatomic_ops/src/atomic_ops.h"
  3. #ifdef __APPLE__
  4. #include <libkern/OSAtomic.h>
  5. #endif
  6. //#define DEBUG_THREADS
  7. #ifndef __EMSCRIPTEN__
  8. //***** Common *****
  9. int _bbNeedsLock;
  10. bb_mutex_t _bbLock;
  11. static int threadDataId;
  12. static BBThread *threads;
  13. static BBThread *deadThreads;
  14. static BBThread *mainThread;
  15. static void flushDeadThreads(){
  16. BBThread **p=&deadThreads,*t;
  17. while( t=*p ){
  18. if( t->detached ){
  19. *p=t->succ;
  20. #ifdef _WIN32
  21. CloseHandle( t->handle );
  22. #endif
  23. GC_FREE( t );
  24. }else{
  25. p=&t->succ;
  26. }
  27. }
  28. }
  29. static void addThread( BBThread *thread ){
  30. flushDeadThreads();
  31. thread->succ=threads;
  32. threads=thread;
  33. }
  34. static void removeThread( BBThread *thread ){
  35. BBThread **p=&threads,*t;
  36. while( t=*p ){
  37. if( t==thread ){
  38. *p=t->succ;
  39. if( t->detached ){
  40. #ifdef _WIN32
  41. CloseHandle( t->handle );
  42. #endif
  43. GC_FREE( t );
  44. }else{
  45. t->succ=deadThreads;
  46. deadThreads=t;
  47. }
  48. break;
  49. }else{
  50. p=&t->succ;
  51. }
  52. }
  53. }
  54. static void * bbRegisterGCThread(struct GC_stack_base * sb, void * arg) {
  55. GC_register_my_thread(sb);
  56. return NULL;
  57. }
  58. int bbThreadAllocData(){
  59. if( threadDataId<31 ) return ++threadDataId;
  60. return 0;
  61. }
  62. void bbThreadSetData( int index,BBObject *data ){
  63. bbThreadGetCurrent()->data[index]=data;
  64. }
  65. BBObject *bbThreadGetData( int index ){
  66. BBObject * data = bbThreadGetCurrent()->data[index];
  67. return data ? data : &bbNullObject;
  68. }
  69. //***** Windows threads *****
  70. #ifdef _WIN32
  71. static DWORD curThreadTls;
  72. static DWORD WINAPI threadProc( void *p ){
  73. BBThread *thread=p;
  74. TlsSetValue( curThreadTls,thread );
  75. BBObject * result = thread->proc( thread->data[0] );
  76. thread->result = result;
  77. BB_LOCK
  78. removeThread( thread );
  79. BB_UNLOCK
  80. return 0;
  81. }
  82. void bbThreadPreStartup(){
  83. }
  84. void bbThreadStartup(){
  85. if( bb_mutex_init( &_bbLock )<0 ) exit(-1);
  86. curThreadTls=TlsAlloc();
  87. BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
  88. thread->proc=0;
  89. memset( thread->data,0,sizeof(thread->data) );
  90. thread->detached=0;
  91. thread->id=GetCurrentThreadId();
  92. if( !DuplicateHandle( GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&thread->handle,0,FALSE,DUPLICATE_SAME_ACCESS ) ){
  93. exit( -1 );
  94. }
  95. TlsSetValue( curThreadTls,thread );
  96. thread->succ=threads;
  97. threads=thread;
  98. mainThread=thread;
  99. }
  100. BBThread *bbThreadCreate( BBThreadProc proc,BBObject *data ){
  101. BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
  102. thread->proc=proc;
  103. memset( thread->data,0,sizeof(thread->data) );
  104. thread->data[0]=data;
  105. thread->detached=0;
  106. thread->result = &bbNullObject;
  107. thread->handle=CreateThread( 0,0,threadProc,thread,CREATE_SUSPENDED,&thread->id );
  108. BB_LOCK
  109. addThread( thread );
  110. BB_UNLOCK
  111. _bbNeedsLock=1;
  112. return thread;
  113. }
  114. void bbThreadDetach( BBThread *thread ){
  115. thread->detached=1;
  116. }
  117. BBObject *bbThreadWait( BBThread *thread ){
  118. if( WaitForSingleObject( thread->handle,INFINITE )==WAIT_OBJECT_0 ){
  119. DWORD res;
  120. if( GetExitCodeThread( thread->handle, &res ) ){
  121. thread->detached=1;
  122. return thread->result;
  123. }else{
  124. printf( "ERROR! bbThreadWait: GetExitCodeThread failed!\n" );
  125. }
  126. }else{
  127. printf( "ERROR! bbThreadWait: WaitForSingleObject failed!\n" );
  128. }
  129. printf( "LastError=%i\n",GetLastError() );
  130. return &bbNullObject;
  131. }
  132. BBThread *bbThreadGetMain(){
  133. return mainThread;
  134. }
  135. BBThread *bbThreadGetCurrent(){
  136. return TlsGetValue( curThreadTls );
  137. }
  138. int bbThreadSuspend( BBThread *thread ){
  139. return SuspendThread( thread->handle );
  140. }
  141. int bbThreadResume( BBThread *thread ){
  142. return ResumeThread( thread->handle );
  143. }
  144. BBThread *bbThreadRegister( DWORD id ) {
  145. GC_call_with_stack_base(bbRegisterGCThread, NULL);
  146. BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
  147. memset( thread->data,0,sizeof(thread->data) );
  148. thread->handle = 0;
  149. thread->proc=0;
  150. thread->data[0]=0;
  151. thread->detached=0;
  152. thread->id = id;
  153. TlsSetValue( curThreadTls,thread );
  154. BB_LOCK
  155. addThread( thread );
  156. BB_UNLOCK
  157. return thread;
  158. }
  159. void bbThreadUnregister( BBThread * thread ) {
  160. GC_unregister_my_thread();
  161. BB_LOCK
  162. removeThread( thread );
  163. BB_UNLOCK
  164. }
  165. #elif __SWITCH__
  166. static __thread BBThread * bbThread;
  167. void bbThreadPreStartup(){
  168. }
  169. void bbThreadStartup() {
  170. BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
  171. thread->proc=0;
  172. thread->detached=0;
  173. thread->handle=thrd_current();
  174. bbThread = thread;
  175. thread->succ=threads;
  176. threads=thread;
  177. mainThread=thread;
  178. }
  179. static BBObject * threadProc( void *p ){
  180. GC_call_with_stack_base(bbRegisterGCThread, NULL);
  181. BBThread *thread = p;
  182. bbThread = thread;
  183. BB_LOCK
  184. addThread( thread );
  185. BB_UNLOCK
  186. #ifdef DEBUG_THREADS
  187. printf( "Thread %p added\n",thread );fflush( stdout );
  188. #endif
  189. BBObject * ret=thread->proc( thread->data[0] );
  190. GC_unregister_my_thread();
  191. BB_LOCK
  192. removeThread( thread );
  193. BB_UNLOCK
  194. #ifdef DEBUG_THREADS
  195. printf( "Thread %p removed\n",thread );fflush( stdout );
  196. #endif
  197. return ret;
  198. }
  199. BBThread * bbThreadCreate( BBThreadProc proc,BBObject *data ) {
  200. BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
  201. memset( thread->data,0,sizeof(thread->data) );
  202. thread->proc=proc;
  203. thread->data[0]=data;
  204. thread->detached=0;
  205. if( thrd_create( &thread->handle,threadProc,thread ) == thrd_success ){
  206. _bbNeedsLock=1;
  207. return thread;
  208. }
  209. GC_FREE( thread );
  210. return 0;
  211. }
  212. void bbThreadDetach( BBThread *thread ) {
  213. thread->detached=1;
  214. // thrd_detach( thread->handle );
  215. }
  216. BBObject * bbThreadWait( BBThread *thread ) {
  217. BBObject *p=0;
  218. thread->detached=1;
  219. thrd_join( thread->handle,&p );
  220. return p;
  221. }
  222. BBThread * bbThreadGetMain() {
  223. return mainThread;
  224. }
  225. BBThread * bbThreadGetCurrent() {
  226. return bbThread;
  227. }
  228. int bbThreadResume( BBThread *thread ) {
  229. return 0;
  230. }
  231. //***** POSIX threads *****
  232. #else
  233. #include <unistd.h>
  234. #include <signal.h>
  235. #if __linux
  236. #define MUTEX_RECURSIVE 1
  237. #elif __APPLE__
  238. #define MUTEX_RECURSIVE 2
  239. #elif __SWITCH__
  240. #define MUTEX_RECURSIVE 1
  241. #elif __HAIKU__
  242. #define MUTEX_RECURSIVE 3
  243. #endif
  244. pthread_mutexattr_t _bb_mutexattr;
  245. static BBThread *threads;
  246. static pthread_key_t curThreadTls;
  247. void bbThreadPreStartup(){
  248. if( pthread_mutexattr_init( &_bb_mutexattr )<0 ) exit(-1);
  249. if( pthread_mutexattr_settype( &_bb_mutexattr,MUTEX_RECURSIVE )<0 ) exit(-1);
  250. }
  251. void bbThreadStartup(){
  252. if( pthread_key_create( &curThreadTls,0 )<0 ) exit(-1);
  253. if( bb_mutex_init( &_bbLock )<0 ) exit(-1);
  254. BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
  255. memset( thread->data,0,sizeof(thread->data) );
  256. thread->proc=0;
  257. thread->detached=0;
  258. thread->handle=pthread_self();
  259. pthread_setspecific( curThreadTls,thread );
  260. thread->succ=threads;
  261. threads=thread;
  262. mainThread=thread;
  263. }
  264. static void *threadProc( void *p ){
  265. GC_call_with_stack_base(bbRegisterGCThread, NULL);
  266. BBThread *thread=p;
  267. pthread_setspecific( curThreadTls,thread );
  268. BB_LOCK
  269. addThread( thread );
  270. BB_UNLOCK
  271. #ifdef DEBUG_THREADS
  272. printf( "Thread %p added\n",thread );fflush( stdout );
  273. #endif
  274. void *ret=thread->proc( thread->data[0] );
  275. GC_unregister_my_thread();
  276. BB_LOCK
  277. removeThread( thread );
  278. BB_UNLOCK
  279. #ifdef DEBUG_THREADS
  280. printf( "Thread %p removed\n",thread );fflush( stdout );
  281. #endif
  282. return ret;
  283. }
  284. BBThread *bbThreadCreate( BBThreadProc proc,BBObject *data ){
  285. BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
  286. memset( thread->data,0,sizeof(thread->data) );
  287. thread->proc=proc;
  288. thread->data[0]=data;
  289. thread->detached=0;
  290. if( pthread_create( &thread->handle,0,threadProc,thread )==0 ){
  291. _bbNeedsLock=1;
  292. return thread;
  293. }
  294. GC_FREE( thread );
  295. return 0;
  296. }
  297. BBThread *bbThreadRegister( void * thd ) {
  298. GC_call_with_stack_base(bbRegisterGCThread, NULL);
  299. BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
  300. memset( thread->data,0,sizeof(thread->data) );
  301. thread->handle = thd;
  302. thread->proc=0;
  303. thread->data[0]=0;
  304. thread->detached=0;
  305. pthread_setspecific( curThreadTls,thread );
  306. BB_LOCK
  307. addThread( thread );
  308. BB_UNLOCK
  309. return thread;
  310. }
  311. void bbThreadUnregister( BBThread * thread ) {
  312. GC_unregister_my_thread();
  313. BB_LOCK
  314. removeThread( thread );
  315. BB_UNLOCK
  316. }
  317. void bbThreadDetach( BBThread *thread ){
  318. thread->detached=1;
  319. pthread_detach( thread->handle );
  320. }
  321. BBObject *bbThreadWait( BBThread *thread ){
  322. BBObject *p=0;
  323. thread->detached=1;
  324. pthread_join( thread->handle,&p );
  325. return p;
  326. }
  327. BBThread *bbThreadGetMain(){
  328. return mainThread;
  329. }
  330. BBThread *bbThreadGetCurrent(){
  331. return pthread_getspecific( curThreadTls );
  332. }
  333. int bbThreadResume( BBThread *thread ){
  334. return 0;
  335. }
  336. #endif
  337. //***** Atomic ops *****
  338. int bbAtomicCAS( volatile int *addr,int old,int new_val ){
  339. #if !defined(__ANDROID__) && !defined(_WIN32)
  340. # ifndef __APPLE__
  341. return __sync_bool_compare_and_swap(addr, old, new_val);
  342. # else
  343. return OSAtomicCompareAndSwap32(old, new_val, addr);
  344. # endif
  345. #else
  346. return __sync_bool_compare_and_swap(addr, old, new_val);
  347. #endif
  348. }
  349. int bbAtomicAdd( volatile int *p,int incr ){
  350. #if !defined(__ANDROID__) && !defined(_WIN32)
  351. # ifndef __APPLE__
  352. return __sync_fetch_and_add(p, incr);
  353. # else
  354. return OSAtomicAdd32(incr, p);
  355. # endif
  356. #else
  357. return __sync_fetch_and_add(p, incr);
  358. #endif
  359. }
  360. #endif // __EMSCRIPTEN__