blitz_thread.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  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( bb_thread_t 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. #define MUTEX_POLICY_FIRSTFIT 3
  240. #elif __SWITCH__
  241. #define MUTEX_RECURSIVE 1
  242. #elif __HAIKU__
  243. #define MUTEX_RECURSIVE 3
  244. #endif
  245. pthread_mutexattr_t _bb_mutexattr;
  246. static BBThread *threads;
  247. static pthread_key_t curThreadTls;
  248. void bbThreadPreStartup(){
  249. if( pthread_mutexattr_init( &_bb_mutexattr )<0 ) exit(-1);
  250. if( pthread_mutexattr_settype( &_bb_mutexattr,MUTEX_RECURSIVE )<0 ) exit(-1);
  251. #if __APPLE__
  252. // can fail on 10.13 or lower, which we ignore
  253. pthread_mutexattr_setpolicy_np(&_bb_mutexattr, MUTEX_POLICY_FIRSTFIT);
  254. #endif
  255. }
  256. void bbThreadStartup(){
  257. if( pthread_key_create( &curThreadTls,0 )<0 ) exit(-1);
  258. if( bb_mutex_init( &_bbLock )<0 ) exit(-1);
  259. BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
  260. memset( thread->data,0,sizeof(thread->data) );
  261. thread->proc=0;
  262. thread->detached=0;
  263. thread->handle=pthread_self();
  264. pthread_setspecific( curThreadTls,thread );
  265. thread->succ=threads;
  266. threads=thread;
  267. mainThread=thread;
  268. }
  269. static void *threadProc( void *p ){
  270. GC_call_with_stack_base(bbRegisterGCThread, NULL);
  271. BBThread *thread=(BBThread *)p;
  272. pthread_setspecific( curThreadTls,thread );
  273. BB_LOCK
  274. addThread( thread );
  275. BB_UNLOCK
  276. #ifdef DEBUG_THREADS
  277. printf( "Thread %p added\n",thread );fflush( stdout );
  278. #endif
  279. void *ret=thread->proc( thread->data[0] );
  280. GC_unregister_my_thread();
  281. BB_LOCK
  282. removeThread( thread );
  283. BB_UNLOCK
  284. #ifdef DEBUG_THREADS
  285. printf( "Thread %p removed\n",thread );fflush( stdout );
  286. #endif
  287. return ret;
  288. }
  289. BBThread *bbThreadCreate( BBThreadProc proc,BBObject *data ){
  290. BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
  291. memset( thread->data,0,sizeof(thread->data) );
  292. thread->proc=proc;
  293. thread->data[0]=data;
  294. thread->detached=0;
  295. if( pthread_create( &thread->handle,0,threadProc,thread )==0 ){
  296. _bbNeedsLock=1;
  297. return thread;
  298. }
  299. GC_FREE( thread );
  300. return 0;
  301. }
  302. BBThread *bbThreadRegister( bb_thread_t thd ) {
  303. GC_call_with_stack_base(bbRegisterGCThread, NULL);
  304. BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
  305. memset( thread->data,0,sizeof(thread->data) );
  306. thread->handle = thd;
  307. thread->proc=0;
  308. thread->data[0]=0;
  309. thread->detached=0;
  310. pthread_setspecific( curThreadTls,thread );
  311. BB_LOCK
  312. addThread( thread );
  313. BB_UNLOCK
  314. return thread;
  315. }
  316. void bbThreadUnregister( BBThread * thread ) {
  317. GC_unregister_my_thread();
  318. BB_LOCK
  319. removeThread( thread );
  320. BB_UNLOCK
  321. }
  322. void bbThreadDetach( BBThread *thread ){
  323. thread->detached=1;
  324. pthread_detach( thread->handle );
  325. }
  326. BBObject *bbThreadWait( BBThread *thread ){
  327. BBObject *p=0;
  328. thread->detached=1;
  329. pthread_join( thread->handle,(void**)&p );
  330. return p;
  331. }
  332. BBThread *bbThreadGetMain(){
  333. return mainThread;
  334. }
  335. BBThread *bbThreadGetCurrent(){
  336. return pthread_getspecific( curThreadTls );
  337. }
  338. int bbThreadResume( BBThread *thread ){
  339. return 0;
  340. }
  341. #endif
  342. //***** Atomic ops *****
  343. int bbAtomicCAS( volatile int *addr,int old,int new_val ){
  344. #if !defined(__ANDROID__) && !defined(_WIN32)
  345. # ifndef __APPLE__
  346. return __sync_bool_compare_and_swap(addr, old, new_val);
  347. # else
  348. return OSAtomicCompareAndSwap32(old, new_val, addr);
  349. # endif
  350. #else
  351. return __sync_bool_compare_and_swap(addr, old, new_val);
  352. #endif
  353. }
  354. int bbAtomicAdd( volatile int *p,int incr ){
  355. #if !defined(__ANDROID__) && !defined(_WIN32)
  356. # ifndef __APPLE__
  357. return __sync_fetch_and_add(p, incr);
  358. # else
  359. return OSAtomicAdd32(incr, p);
  360. # endif
  361. #else
  362. return __sync_fetch_and_add(p, incr);
  363. #endif
  364. }
  365. #endif // __EMSCRIPTEN__