2
0

blitz_thread.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. #include "blitz.h"
  2. //#define DEBUG_THREADS
  3. //***** Common *****
  4. int _bbNeedsLock;
  5. bb_mutex_t _bbLock;
  6. static int threadDataId;
  7. static BBThread *threads;
  8. static BBThread *deadThreads;
  9. static BBThread *mainThread;
  10. static void flushDeadThreads(){
  11. BBThread **p=&deadThreads,*t;
  12. while( t=*p ){
  13. if( t->detached ){
  14. *p=t->succ;
  15. #ifdef _WIN32
  16. CloseHandle( t->handle );
  17. #endif
  18. free( t );
  19. }else{
  20. p=&t->succ;
  21. }
  22. }
  23. }
  24. static void addThread( BBThread *thread ){
  25. flushDeadThreads();
  26. thread->succ=threads;
  27. threads=thread;
  28. }
  29. static void removeThread( BBThread *thread ){
  30. BBThread **p=&threads,*t;
  31. while( t=*p ){
  32. if( t==thread ){
  33. *p=t->succ;
  34. if( t->detached ){
  35. #ifdef _WIN32
  36. CloseHandle( t->handle );
  37. #endif
  38. free( t );
  39. }else{
  40. t->succ=deadThreads;
  41. deadThreads=t;
  42. }
  43. break;
  44. }else{
  45. p=&t->succ;
  46. }
  47. }
  48. }
  49. int bbThreadAllocData(){
  50. if( threadDataId<31 ) return ++threadDataId;
  51. return 0;
  52. }
  53. void bbThreadSetData( int index,BBObject *data ){
  54. bbThreadGetCurrent()->data[index]=data;
  55. }
  56. BBObject *bbThreadGetData( int index ){
  57. BBObject *data=bbThreadGetCurrent()->data[index];
  58. return data ? data : &bbNullObject;
  59. }
  60. //***** Windows threads *****
  61. #ifdef _WIN32
  62. static DWORD curThreadTls;
  63. static DWORD WINAPI threadProc( void *p ){
  64. BBThread *thread=p;
  65. TlsSetValue( curThreadTls,thread );
  66. DWORD ret=(DWORD)thread->proc( thread->data[0] );
  67. BB_LOCK
  68. removeThread( thread );
  69. BB_UNLOCK
  70. return ret;
  71. }
  72. void bbThreadStartup(){
  73. if( bb_mutex_init( &_bbLock )<0 ) exit(-1);
  74. curThreadTls=TlsAlloc();
  75. BBThread *thread=malloc( sizeof( BBThread ) );
  76. thread->proc=0;
  77. memset( thread->data,0,sizeof(thread->data) );
  78. thread->detached=0;
  79. thread->stackTop=bbGCStackTop;
  80. thread->id=GetCurrentThreadId();
  81. if( !DuplicateHandle( GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&thread->handle,0,FALSE,DUPLICATE_SAME_ACCESS ) ){
  82. exit( -1 );
  83. }
  84. TlsSetValue( curThreadTls,thread );
  85. thread->succ=threads;
  86. threads=thread;
  87. mainThread=thread;
  88. }
  89. BBThread *bbThreadCreate( BBThreadProc proc,BBObject *data ){
  90. BBThread *thread=malloc( sizeof( BBThread ) );
  91. thread->proc=proc;
  92. memset( thread->data,0,sizeof(thread->data) );
  93. thread->data[0]=data;
  94. thread->detached=0;
  95. thread->handle=CreateThread( 0,0,threadProc,thread,CREATE_SUSPENDED,&thread->id );
  96. CONTEXT ctx={CONTEXT_CONTROL};
  97. GetThreadContext( thread->handle,&ctx );
  98. thread->stackTop=ctx.Esp;
  99. BB_LOCK
  100. addThread( thread );
  101. BB_UNLOCK
  102. _bbNeedsLock=1;
  103. return thread;
  104. }
  105. void bbThreadDetach( BBThread *thread ){
  106. thread->detached=1;
  107. }
  108. BBObject *bbThreadWait( BBThread *thread ){
  109. if( WaitForSingleObject( thread->handle,INFINITE )==WAIT_OBJECT_0 ){
  110. BBObject *p;
  111. if( GetExitCodeThread( thread->handle,(DWORD*)&p ) ){
  112. thread->detached=1;
  113. return p;
  114. }else{
  115. printf( "ERROR! bbThreadWait: GetExitCodeThread failed!\n" );
  116. }
  117. }else{
  118. printf( "ERROR! bbThreadWait: WaitForSingleObject failed!\n" );
  119. }
  120. printf( "LastError=%i\n",GetLastError() );
  121. return &bbNullObject;
  122. }
  123. BBThread *bbThreadGetMain(){
  124. return mainThread;
  125. }
  126. BBThread *bbThreadGetCurrent(){
  127. return TlsGetValue( curThreadTls );
  128. }
  129. int bbThreadSuspend( BBThread *thread ){
  130. return SuspendThread( thread->handle );
  131. }
  132. int bbThreadResume( BBThread *thread ){
  133. return ResumeThread( thread->handle );
  134. }
  135. BBThread *_bbThreadLockThreads(){
  136. BBThread *curThread=bbThreadGetCurrent();
  137. BBThread *t;
  138. for( t=threads;t;t=t->succ ){
  139. if( t!=curThread ){
  140. SuspendThread( t->handle );
  141. CONTEXT ctx={CONTEXT_INTEGER|CONTEXT_CONTROL};
  142. GetThreadContext( t->handle,&ctx );
  143. t->locked_regs[0]=ctx.Edi;
  144. t->locked_regs[1]=ctx.Esi;
  145. t->locked_regs[2]=ctx.Ebx;
  146. t->locked_regs[3]=ctx.Edx;
  147. t->locked_regs[4]=ctx.Ecx;
  148. t->locked_regs[5]=ctx.Eax;
  149. t->locked_regs[6]=ctx.Ebp;
  150. t->locked_sp=ctx.Esp;
  151. }
  152. }
  153. return threads;
  154. }
  155. void _bbThreadUnlockThreads(){
  156. BBThread *curThread=bbThreadGetCurrent();
  157. BBThread *t;
  158. for( t=threads;t;t=t->succ ){
  159. if( t!=curThread ){
  160. ResumeThread( t->handle );
  161. }
  162. }
  163. }
  164. //***** POSIX threads *****
  165. #else
  166. #include <unistd.h>
  167. #include <signal.h>
  168. #if __linux
  169. #define MUTEX_RECURSIVE 1
  170. #elif __APPLE__
  171. #define MUTEX_RECURSIVE 2
  172. #endif
  173. pthread_mutexattr_t _bb_mutexattr;
  174. static BBThread *threads;
  175. static pthread_key_t curThreadTls;
  176. static void suspendSigHandler( int sig ){//,siginfo_t *info,ucontext_t *ctx ){
  177. BBThread *thread=pthread_getspecific( curThreadTls );
  178. thread->locked_sp=bbGCRootRegs( thread->locked_regs );
  179. #ifdef DEBUG_THREADS
  180. printf( "In suspendSigHandler! thread=%p locked_sp=%p\n",thread,thread->locked_sp );fflush( stdout );
  181. #endif
  182. bb_sem_post( &thread->acksema );
  183. //wait for resume - apparently very naughty!
  184. bb_sem_wait( &thread->runsema );
  185. #ifdef DEBUG_THREADS
  186. printf( "Got resume!\n" );fflush( stdout );
  187. #endif
  188. }
  189. void bbThreadStartup(){
  190. if( pthread_mutexattr_init( &_bb_mutexattr )<0 ) exit(-1);
  191. if( pthread_mutexattr_settype( &_bb_mutexattr,MUTEX_RECURSIVE )<0 ) exit(-1);
  192. if( pthread_key_create( &curThreadTls,0 )<0 ) exit(-1);
  193. if( bb_mutex_init( &_bbLock )<0 ) exit(-1);
  194. struct sigaction act;
  195. memset( &act,0,sizeof(act) );
  196. act.sa_handler=suspendSigHandler;
  197. act.sa_flags=SA_RESTART;
  198. if( sigaction( SIGUSR2,&act,0 )<0 ) exit(-1);
  199. BBThread *thread=malloc( sizeof( BBThread ) );
  200. memset( thread->data,0,sizeof(thread->data) );
  201. thread->proc=0;
  202. thread->detached=0;
  203. thread->suspended=0;
  204. thread->handle=pthread_self();
  205. if( !bb_sem_init( &thread->runsema,0 ) ) exit(-1);
  206. if( !bb_sem_init( &thread->acksema,0 ) ) exit(-1);
  207. thread->stackTop=bbGCStackTop;
  208. pthread_setspecific( curThreadTls,thread );
  209. thread->succ=threads;
  210. threads=thread;
  211. mainThread=thread;
  212. }
  213. static void *threadProc( void *p ){
  214. BBThread *thread=p;
  215. thread->stackTop=bbGCRootRegs( thread->locked_regs );
  216. pthread_setspecific( curThreadTls,thread );
  217. BB_LOCK
  218. addThread( thread );
  219. BB_UNLOCK
  220. bb_sem_post( &thread->acksema );
  221. bb_sem_wait( &thread->runsema );
  222. #ifdef DEBUG_THREADS
  223. printf( "Thread %p added, stackTop=%p\n",thread,thread->stackTop );fflush( stdout );
  224. #endif
  225. void *ret=thread->proc( thread->data[0] );
  226. BB_LOCK
  227. removeThread( thread );
  228. BB_UNLOCK
  229. bb_sem_destroy( &thread->runsema );
  230. bb_sem_destroy( &thread->acksema );
  231. #ifdef DEBUG_THREADS
  232. printf( "Thread %p removed\n",thread );fflush( stdout );
  233. #endif
  234. return ret;
  235. }
  236. BBThread *bbThreadCreate( BBThreadProc proc,BBObject *data ){
  237. BBThread *thread=malloc( sizeof( BBThread ) );
  238. memset( thread->data,0,sizeof(thread->data) );
  239. thread->proc=proc;
  240. thread->data[0]=data;
  241. thread->detached=0;
  242. thread->suspended=1;
  243. if( bb_sem_init( &thread->runsema,0 ) ){
  244. if( bb_sem_init( &thread->acksema,0 ) ){
  245. if( pthread_create( &thread->handle,0,threadProc,thread )>=0 ){
  246. bb_sem_wait( &thread->acksema );
  247. _bbNeedsLock=1;
  248. return thread;
  249. }
  250. bb_sem_destroy( &thread->acksema );
  251. }
  252. bb_sem_destroy( &thread->runsema );
  253. }
  254. free( thread );
  255. return 0;
  256. }
  257. void bbThreadDetach( BBThread *thread ){
  258. thread->detached=1;
  259. pthread_detach( thread->handle );
  260. }
  261. BBObject *bbThreadWait( BBThread *thread ){
  262. BBObject *p=0;
  263. thread->detached=1;
  264. pthread_join( thread->handle,&p );
  265. return p;
  266. }
  267. BBThread *bbThreadGetMain(){
  268. return mainThread;
  269. }
  270. BBThread *bbThreadGetCurrent(){
  271. return pthread_getspecific( curThreadTls );
  272. }
  273. int bbThreadSuspend( BBThread *thread ){
  274. BB_LOCK
  275. int n=thread->suspended++;
  276. if( n==0 ){
  277. pthread_kill( thread->handle,SIGUSR2 );
  278. bb_sem_wait( &thread->acksema );
  279. }
  280. BB_UNLOCK
  281. return n;
  282. }
  283. int bbThreadResume( BBThread *thread ){
  284. BB_LOCK
  285. int n=thread->suspended--;
  286. if( n==1 ){
  287. bb_sem_post( &thread->runsema );
  288. }
  289. BB_UNLOCK
  290. return n;
  291. }
  292. BBThread *_bbThreadLockThreads(){
  293. BBThread *curThread=bbThreadGetCurrent();
  294. BBThread *t;
  295. for( t=threads;t;t=t->succ ){
  296. if( t!=curThread ){
  297. if( !t->suspended++ ){
  298. pthread_kill( t->handle,SIGUSR2 );
  299. bb_sem_wait( &t->acksema );
  300. }
  301. }
  302. }
  303. return threads;
  304. }
  305. void _bbThreadUnlockThreads(){
  306. BBThread *curThread=bbThreadGetCurrent();
  307. BBThread *t;
  308. for( t=threads;t;t=t->succ ){
  309. if( t!=curThread ){
  310. if( !--t->suspended ){
  311. bb_sem_post( &t->runsema );
  312. }
  313. }
  314. }
  315. }
  316. #endif
  317. //***** Atomic ops *****
  318. #if __ppc__
  319. int bbAtomicCAS( volatile int *addr,int old,int new_val ){
  320. int oldval;
  321. int result=0;
  322. __asm__ __volatile__(
  323. "1:lwarx %0,0,%2\n" /* load and reserve */
  324. "cmpw %0, %4\n" /* if load is not equal to */
  325. "bne 2f\n" /* old, fail */
  326. "stwcx. %3,0,%2\n" /* else store conditional */
  327. "bne- 1b\n" /* retry if lost reservation */
  328. "li %1,1\n" /* result = 1; */
  329. "2:\n"
  330. : "=&r"(oldval), "=&r"(result)
  331. : "r"(addr), "r"(new_val), "r"(old), "1"(result)
  332. : "memory", "cc");
  333. return result;
  334. }
  335. int bbAtomicAdd( volatile int *p,int incr ){
  336. int old;
  337. for(;;){
  338. old=*p;
  339. if( bbAtomicCAS( p,old,old+incr ) ) return old;
  340. }
  341. }
  342. #else
  343. int bbAtomicCAS( volatile int *addr,int old,int new_val ){
  344. char result;
  345. __asm__ __volatile__(
  346. "lock; cmpxchgl %3, %0; setz %1"
  347. : "=m"(*addr), "=q"(result)
  348. : "m"(*addr), "r" (new_val), "a"(old) : "memory");
  349. return (int)result;
  350. }
  351. int bbAtomicAdd( volatile int *p,int incr ){
  352. int result;
  353. __asm__ __volatile__ ("lock; xaddl %0, %1" :
  354. "=r" (result), "=m" (*p) : "0" (incr), "m" (*p)
  355. : "memory");
  356. return result;
  357. }
  358. #endif