123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 |
- #include "blitz.h"
- #include "bdwgc/libatomic_ops/src/atomic_ops.h"
- #ifdef __APPLE__
- #include <libkern/OSAtomic.h>
- #endif
- //#define DEBUG_THREADS
- #ifndef __EMSCRIPTEN__
- //***** Common *****
- int _bbNeedsLock;
- bb_mutex_t _bbLock;
- static int threadDataId;
- static BBThread *threads;
- static BBThread *deadThreads;
- static BBThread *mainThread;
- static void flushDeadThreads(){
- BBThread **p=&deadThreads,*t;
- while( t=*p ){
- if( t->detached ){
- *p=t->succ;
- #ifdef _WIN32
- CloseHandle( t->handle );
- #endif
- GC_FREE( t );
- }else{
- p=&t->succ;
- }
- }
- }
- static void addThread( BBThread *thread ){
- flushDeadThreads();
- thread->succ=threads;
- threads=thread;
- }
- static void removeThread( BBThread *thread ){
- BBThread **p=&threads,*t;
- while( t=*p ){
- if( t==thread ){
- *p=t->succ;
- if( t->detached ){
- #ifdef _WIN32
- CloseHandle( t->handle );
- #endif
- GC_FREE( t );
- }else{
- t->succ=deadThreads;
- deadThreads=t;
- }
- break;
- }else{
- p=&t->succ;
- }
- }
- }
- static void * bbRegisterGCThread(struct GC_stack_base * sb, void * arg) {
- GC_register_my_thread(sb);
- return NULL;
- }
- int bbThreadAllocData(){
- if( threadDataId<31 ) return ++threadDataId;
- return 0;
- }
- void bbThreadSetData( int index,BBObject *data ){
- bbThreadGetCurrent()->data[index]=data;
- }
- BBObject *bbThreadGetData( int index ){
- BBObject * data = bbThreadGetCurrent()->data[index];
- return data ? data : &bbNullObject;
- }
- //***** Windows threads *****
- #ifdef _WIN32
- static DWORD curThreadTls;
- static DWORD WINAPI threadProc( void *p ){
- BBThread *thread=p;
-
- TlsSetValue( curThreadTls,thread );
-
- BBObject * result = thread->proc( thread->data[0] );
- thread->result = result;
- BB_LOCK
- removeThread( thread );
- BB_UNLOCK
-
- return 0;
- }
- void bbThreadPreStartup(){
- }
- void bbThreadStartup(){
- if( bb_mutex_init( &_bbLock )<0 ) exit(-1);
- curThreadTls=TlsAlloc();
- BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
-
- thread->proc=0;
- memset( thread->data,0,sizeof(thread->data) );
- thread->detached=0;
- thread->id=GetCurrentThreadId();
- if( !DuplicateHandle( GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&thread->handle,0,FALSE,DUPLICATE_SAME_ACCESS ) ){
- exit( -1 );
- }
- TlsSetValue( curThreadTls,thread );
-
- thread->succ=threads;
- threads=thread;
- mainThread=thread;
- }
- BBThread *bbThreadCreate( BBThreadProc proc,BBObject *data ){
- BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
-
- thread->proc=proc;
- memset( thread->data,0,sizeof(thread->data) );
- thread->data[0]=data;
- thread->detached=0;
- thread->result = &bbNullObject;
- thread->handle=CreateThread( 0,0,threadProc,thread,CREATE_SUSPENDED,&thread->id );
- BB_LOCK
- addThread( thread );
- BB_UNLOCK
- _bbNeedsLock=1;
-
- return thread;
- }
- void bbThreadDetach( BBThread *thread ){
- thread->detached=1;
- }
- BBObject *bbThreadWait( BBThread *thread ){
- if( WaitForSingleObject( thread->handle,INFINITE )==WAIT_OBJECT_0 ){
- DWORD res;
- if( GetExitCodeThread( thread->handle, &res ) ){
- thread->detached=1;
- return thread->result;
- }else{
- printf( "ERROR! bbThreadWait: GetExitCodeThread failed!\n" );
- }
- }else{
- printf( "ERROR! bbThreadWait: WaitForSingleObject failed!\n" );
- }
- printf( "LastError=%i\n",GetLastError() );
-
- return &bbNullObject;
- }
- BBThread *bbThreadGetMain(){
- return mainThread;
- }
- BBThread *bbThreadGetCurrent(){
- return TlsGetValue( curThreadTls );
- }
- int bbThreadSuspend( BBThread *thread ){
- return SuspendThread( thread->handle );
- }
- int bbThreadResume( BBThread *thread ){
- return ResumeThread( thread->handle );
- }
- BBThread *bbThreadRegister( bb_thread_t id ) {
- GC_call_with_stack_base(bbRegisterGCThread, NULL);
- BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
- memset( thread->data,0,sizeof(thread->data) );
-
- thread->handle = 0;
- thread->proc=0;
- thread->data[0]=0;
- thread->detached=0;
- thread->id = id;
-
- TlsSetValue( curThreadTls,thread );
- BB_LOCK
- addThread( thread );
- BB_UNLOCK
-
- return thread;
- }
- void bbThreadUnregister( BBThread * thread ) {
- GC_unregister_my_thread();
- BB_LOCK
- removeThread( thread );
- BB_UNLOCK
- }
- #elif __SWITCH__
- static __thread BBThread * bbThread;
- void bbThreadPreStartup(){
- }
- void bbThreadStartup() {
- BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
-
- thread->proc=0;
- thread->detached=0;
- thread->handle=thrd_current();
- bbThread = thread;
- thread->succ=threads;
- threads=thread;
- mainThread=thread;
- }
- static BBObject * threadProc( void *p ){
- GC_call_with_stack_base(bbRegisterGCThread, NULL);
- BBThread *thread = p;
-
- bbThread = thread;
-
- BB_LOCK
- addThread( thread );
- BB_UNLOCK
-
- #ifdef DEBUG_THREADS
- printf( "Thread %p added\n",thread );fflush( stdout );
- #endif
-
- BBObject * ret=thread->proc( thread->data[0] );
-
- GC_unregister_my_thread();
-
- BB_LOCK
- removeThread( thread );
- BB_UNLOCK
-
- #ifdef DEBUG_THREADS
- printf( "Thread %p removed\n",thread );fflush( stdout );
- #endif
-
- return ret;
- }
- BBThread * bbThreadCreate( BBThreadProc proc,BBObject *data ) {
- BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
- memset( thread->data,0,sizeof(thread->data) );
-
- thread->proc=proc;
- thread->data[0]=data;
- thread->detached=0;
- if( thrd_create( &thread->handle,threadProc,thread ) == thrd_success ){
- _bbNeedsLock=1;
- return thread;
- }
- GC_FREE( thread );
- return 0;
- }
- void bbThreadDetach( BBThread *thread ) {
- thread->detached=1;
- // thrd_detach( thread->handle );
- }
- BBObject * bbThreadWait( BBThread *thread ) {
- BBObject *p=0;
- thread->detached=1;
- thrd_join( thread->handle,&p );
- return p;
- }
- BBThread * bbThreadGetMain() {
- return mainThread;
- }
- BBThread * bbThreadGetCurrent() {
- return bbThread;
- }
- int bbThreadResume( BBThread *thread ) {
- return 0;
- }
- //***** POSIX threads *****
- #else
- #include <unistd.h>
- #include <signal.h>
- #if __linux__
- #define MUTEX_RECURSIVE 1
- #elif __APPLE__
- #define MUTEX_RECURSIVE 2
- #define MUTEX_POLICY_FIRSTFIT 3
- #elif __SWITCH__
- #define MUTEX_RECURSIVE 1
- #elif __HAIKU__
- #define MUTEX_RECURSIVE 3
- #endif
- pthread_mutexattr_t _bb_mutexattr;
- static BBThread *threads;
- static pthread_key_t curThreadTls;
- void bbThreadPreStartup(){
- if( pthread_mutexattr_init( &_bb_mutexattr )<0 ) exit(-1);
- if( pthread_mutexattr_settype( &_bb_mutexattr,MUTEX_RECURSIVE )<0 ) exit(-1);
- #if __APPLE__
- // can fail on 10.13 or lower, which we ignore
- pthread_mutexattr_setpolicy_np(&_bb_mutexattr, MUTEX_POLICY_FIRSTFIT);
- #endif
- }
- void bbThreadStartup(){
- if( pthread_key_create( &curThreadTls,0 )<0 ) exit(-1);
- if( bb_mutex_init( &_bbLock )<0 ) exit(-1);
-
- BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
- memset( thread->data,0,sizeof(thread->data) );
-
- thread->proc=0;
- thread->detached=0;
- thread->handle=pthread_self();
- pthread_setspecific( curThreadTls,thread );
-
- thread->succ=threads;
- threads=thread;
- mainThread=thread;
- }
- static void *threadProc( void *p ){
- GC_call_with_stack_base(bbRegisterGCThread, NULL);
- BBThread *thread=(BBThread *)p;
-
- pthread_setspecific( curThreadTls,thread );
-
- BB_LOCK
- addThread( thread );
- BB_UNLOCK
-
- #ifdef DEBUG_THREADS
- printf( "Thread %p added\n",thread );fflush( stdout );
- #endif
-
- void *ret=thread->proc( thread->data[0] );
-
- GC_unregister_my_thread();
-
- BB_LOCK
- removeThread( thread );
- BB_UNLOCK
-
- #ifdef DEBUG_THREADS
- printf( "Thread %p removed\n",thread );fflush( stdout );
- #endif
-
- return ret;
- }
- BBThread *bbThreadCreate( BBThreadProc proc,BBObject *data ){
- BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
- memset( thread->data,0,sizeof(thread->data) );
-
- thread->proc=proc;
- thread->data[0]=data;
- thread->detached=0;
- if( pthread_create( &thread->handle,0,threadProc,thread )==0 ){
- _bbNeedsLock=1;
- return thread;
- }
- GC_FREE( thread );
- return 0;
- }
- BBThread *bbThreadRegister( bb_thread_t thd ) {
- GC_call_with_stack_base(bbRegisterGCThread, NULL);
- BBThread *thread=GC_MALLOC_UNCOLLECTABLE( sizeof( BBThread ) );
- memset( thread->data,0,sizeof(thread->data) );
-
- thread->handle = thd;
- thread->proc=0;
- thread->data[0]=0;
- thread->detached=0;
-
- pthread_setspecific( curThreadTls,thread );
- BB_LOCK
- addThread( thread );
- BB_UNLOCK
-
- return thread;
- }
- void bbThreadUnregister( BBThread * thread ) {
- GC_unregister_my_thread();
- BB_LOCK
- removeThread( thread );
- BB_UNLOCK
- }
- void bbThreadDetach( BBThread *thread ){
- thread->detached=1;
- pthread_detach( thread->handle );
- }
- BBObject *bbThreadWait( BBThread *thread ){
- BBObject *p=0;
- thread->detached=1;
- pthread_join( thread->handle,(void**)&p );
- return p;
- }
- BBThread *bbThreadGetMain(){
- return mainThread;
- }
- BBThread *bbThreadGetCurrent(){
- return pthread_getspecific( curThreadTls );
- }
- int bbThreadResume( BBThread *thread ){
- return 0;
- }
- #endif
- //***** Atomic ops *****
- int bbAtomicCAS( volatile int *addr,int old,int new_val ){
- #if !defined(__ANDROID__) && !defined(_WIN32)
- # ifndef __APPLE__
- return __sync_bool_compare_and_swap(addr, old, new_val);
- # else
- return OSAtomicCompareAndSwap32(old, new_val, addr);
- # endif
- #else
- return __sync_bool_compare_and_swap(addr, old, new_val);
- #endif
- }
- int bbAtomicAdd( volatile int *p,int incr ){
- #if !defined(__ANDROID__) && !defined(_WIN32)
- # ifndef __APPLE__
- return __sync_fetch_and_add(p, incr);
- # else
- return OSAtomicAdd32(incr, p);
- # endif
- #else
- return __sync_fetch_and_add(p, incr);
- #endif
- }
- #endif // __EMSCRIPTEN__
|