@@ -125,6 +125,26 @@ var LibraryPThread = {
125
125
} ,
126
126
#endif
127
127
128
+ #if PTHREADS_DEBUG
129
+ detachStateToString: function ( state ) {
130
+ if ( state === { { { cDefine ( 'DT_EXITED' ) } } } ) return 'DT_EXITED' ;
131
+ if ( state === { { { cDefine ( 'DT_EXITING' ) } } } ) return 'DT_EXITING' ;
132
+ if ( state === { { { cDefine ( 'DT_JOINABLE' ) } } } ) return 'DT_JOINABLE' ;
133
+ if ( state === { { { cDefine ( 'DT_DETACHED' ) } } } ) return 'DT_DETACHED' ;
134
+ assert ( false ) ;
135
+ } ,
136
+ #endif
137
+
138
+ setDetachState : function ( thread , newstate ) {
139
+ #if PTHREADS_DEBUG
140
+ var oldstate = Atomics . load ( HEAPU32 , ( thread + { { { C_STRUCTS . pthread . detach_state } } } ) >> 2 ) ;
141
+ var oldname = PThread . detachStateToString ( oldstate ) ;
142
+ var newname = PThread . detachStateToString ( newstate ) ;
143
+ console . log ( 'thread 0x' + thread . toString ( 16 ) + ' state change: ' + oldname + ' -> ' + newname ) ;
144
+ #endif
145
+ Atomics . store ( HEAPU32 , ( thread + { { { C_STRUCTS . pthread . detach_state } } } ) >> 2 , newstate ) ;
146
+ } ,
147
+
128
148
terminateAllThreads : function ( ) {
129
149
#if ASSERTIONS
130
150
assert ( ! ENVIRONMENT_IS_PTHREAD , 'Internal Error! terminateAllThreads() can only ever be called from main application thread!' ) ;
@@ -278,8 +298,8 @@ var LibraryPThread = {
278
298
} else if ( cmd === 'detachedExit' ) {
279
299
#if ASSERTIONS
280
300
assert ( worker . pthread ) ;
281
- var detached = Atomics . load ( HEAPU32 , ( worker . pthread . threadInfoStruct + { { { C_STRUCTS . pthread . detached } } } ) >> 2 ) ;
282
- assert ( detached ) ;
301
+ var detach_state = Atomics . load ( HEAPU32 , ( worker . pthread . threadInfoStruct + { { { C_STRUCTS . pthread . detach_state } } } ) >> 2 ) ;
302
+ assert ( detach_state == { { { cDefine ( 'DT_EXITED' ) } } } ) ;
283
303
#endif
284
304
PThread . returnWorkerToPool ( worker ) ;
285
305
} else if ( cmd === 'cancelDone' ) {
@@ -570,19 +590,17 @@ var LibraryPThread = {
570
590
worker : worker ,
571
591
stackBase : threadParams . stackBase ,
572
592
stackSize : threadParams . stackSize ,
593
+ initialState : { { { cDefine ( 'DT_JOINABLE' ) } } } ,
573
594
allocatedOwnStack: threadParams . allocatedOwnStack ,
574
595
// Info area for this thread in Emscripten HEAP (shared)
575
596
threadInfoStruct : threadParams . pthread_ptr
576
597
} ;
577
598
var tis = pthread . threadInfoStruct >> 2 ;
578
599
// spawnThread is always called with a zero-initialized thread struct so
579
600
// no need to set any valudes to zero here.
580
- Atomics . store ( HEAPU32 , tis + ( { { { C_STRUCTS . pthread . detached } } } >> 2 ) , threadParams . detached ) ;
601
+ PThread . setDetachState ( pthread . threadInfoStruct , threadParams . initialState ) ;
581
602
Atomics . store ( HEAPU32 , tis + ( { { { C_STRUCTS . pthread . stack_size } } } >> 2 ) , threadParams . stackSize ) ;
582
603
Atomics . store ( HEAPU32 , tis + ( { { { C_STRUCTS . pthread . stack } } } >> 2 ) , stackHigh ) ;
583
- Atomics . store ( HEAPU32 , tis + ( { { { C_STRUCTS . pthread . attr } } } + 0 /*_a_stacksize*/ > > 2 ) , threadParams . stackSize ) ;
584
- Atomics . store ( HEAPU32 , tis + ( { { { C_STRUCTS . pthread . attr } } } + 8 /*_a_stackaddr*/ > > 2 ) , stackHigh ) ;
585
- Atomics . store ( HEAPU32 , tis + ( { { { C_STRUCTS . pthread . attr } } } + 12 /*_a_detach*/ > > 2 ) , threadParams . detached ) ;
586
604
587
605
#if PTHREADS_PROFILING
588
606
PThread . createProfilerBlock ( pthread . threadInfoStruct ) ;
@@ -772,23 +790,16 @@ var LibraryPThread = {
772
790
773
791
var stackSize = 0 ;
774
792
var stackBase = 0 ;
775
- // Default thread attr is PTHREAD_CREATE_JOINABLE , i.e. start as not detached.
776
- var detached = 0 ;
793
+ // Default thread state is DT_JOINABLE , i.e. start as not detached.
794
+ var initialState = { { { cDefine ( 'DT_JOINABLE' ) } } } ;
777
795
// When musl creates C11 threads it passes __ATTRP_C11_THREAD (-1) which
778
796
// treat as if it was NULL.
779
797
if ( attr && attr != { { { cDefine ( '__ATTRP_C11_THREAD' ) } } } ) {
780
798
stackSize = { { { makeGetValue ( 'attr' , 0 /*_a_stacksize*/ , 'i32' ) } } } ;
781
- // Musl has a convention that the stack size that is stored to the pthread
782
- // attribute structure is always musl's #define DEFAULT_STACK_SIZE
783
- // smaller than the actual created stack size. That is, stored stack size
784
- // of 0 would mean a stack of DEFAULT_STACK_SIZE in size. All musl
785
- // functions hide this impl detail, and offset the size transparently, so
786
- // pthread_*() API user does not see this offset when operating with
787
- // the pthread API. When reading the structure directly on JS side
788
- // however, we need to offset the size manually here.
789
- stackSize += { { { cDefine ( 'DEFAULT_STACK_SIZE' ) } } } ;
790
799
stackBase = { { { makeGetValue ( 'attr' , 8 /*_a_stackaddr*/ , 'i32' ) } } } ;
791
- detached = { { { makeGetValue ( 'attr' , 12 /*_a_detach*/ , 'i32' ) } } } !== 0 /*PTHREAD_CREATE_JOINABLE*/ ;
800
+ if ( { { { makeGetValue ( 'attr ', 12 /*_a_detach*/ , 'i32' ) } } } ) {
801
+ initialState = { { { cDefine ( 'DT_DETACHED' ) } } } ;
802
+ }
792
803
} else {
793
804
// According to
794
805
// http://man7.org/linux/man-pages/man3/pthread_create.3.html, default
@@ -822,7 +833,7 @@ var LibraryPThread = {
822
833
stackBase : stackBase ,
823
834
stackSize : stackSize ,
824
835
allocatedOwnStack : allocatedOwnStack ,
825
- detached : detached ,
836
+ initialState : initialState ,
826
837
startRoutine : start_routine ,
827
838
pthread_ptr : pthread_ptr ,
828
839
arg : arg ,
@@ -880,14 +891,19 @@ var LibraryPThread = {
880
891
}
881
892
var self = { { { makeGetValue ( 'thread' , C_STRUCTS . pthread . self , 'i32' ) } } } ;
882
893
if ( self !== thread ) {
883
- err ( 'pthread_join attempted on thread ' + thread + ', which does not point to a valid thread, or does not exist anymore!' ) ;
894
+ err ( 'pthread_join attempted on thread 0x ' + thread . toString ( 16 ) + ', which does not point to a valid thread, or does not exist anymore!' ) ;
884
895
return { { { cDefine ( 'ESRCH' ) } } } ;
885
896
}
886
- var detached = Atomics . load ( HEAPU32 , ( thread + { { { C_STRUCTS . pthread . detached } } } ) >> 2 ) ;
887
- if ( detached ) {
888
- err ( 'Attempted to join thread ' + thread + ', which was already detached!' ) ;
897
+ var detach_state = Atomics . load ( HEAPU32 , ( thread + { { { C_STRUCTS . pthread . detach_state } } } ) >> 2 ) ;
898
+ if ( detach_state == { { { cDefine ( 'DT_DETACHED' ) } } } ) {
899
+ err ( 'Attempted to join thread 0x ' + thread . toString ( 16 ) + ', which was already detached!' ) ;
889
900
return { { { cDefine ( 'EINVAL' ) } } } ; // The thread is already detached, can no longer join it!
890
901
}
902
+
903
+ if ( detach_state == { { { cDefine ( 'DT_EXITED' ) } } } ) {
904
+ err ( 'Attempted to join thread 0x' + thread . toString ( 16 ) + ', which was already joined!' ) ;
905
+ return { { { cDefine ( 'EINVAL' ) } } } ;
906
+ }
891
907
if ( ENVIRONMENT_IS_PTHREAD && _pthread_self ( ) == thread ) {
892
908
err ( 'PThread ' + thread + ' is attempting to join to itself!' ) ;
893
909
return { { { cDefine ( 'EDEADLK' ) } } } ;
@@ -904,14 +920,14 @@ var LibraryPThread = {
904
920
#endif
905
921
906
922
for ( ; ; ) {
907
- var threadStatus = Atomics . load ( HEAPU32 , ( thread + { { { C_STRUCTS . pthread . threadStatus } } } ) >> 2 ) ;
908
- if ( threadStatus == 1 ) { // Exited ?
923
+ var detach_state = Atomics . load ( HEAPU32 , ( thread + { { { C_STRUCTS . pthread . detach_state } } } ) >> 2 ) ;
924
+ if ( detach_state == { { { cDefine ( 'DT_EXITING' ) } } } ) { // Exiting ?
909
925
if ( status ) {
910
926
var result = Atomics . load ( HEAPU32 , ( thread + { { { C_STRUCTS . pthread . result } } } ) >> 2 ) ;
911
927
{ { { makeSetValue ( 'status' , 0 , 'result' , 'i32' ) } } } ;
912
928
}
913
- // Mark the thread as detached .
914
- Atomics . store ( HEAPU32 , ( thread + { { { C_STRUCTS . pthread . detached } } } ) >> 2 , 1 ) ;
929
+ // Mark the thread as exited .
930
+ PThread . setDetachState ( thread , { { { cDefine ( 'DT_EXITED' ) } } } ) ;
915
931
if ( ! ENVIRONMENT_IS_PTHREAD ) cleanupThread ( thread ) ;
916
932
else postMessage ( { 'cmd' : 'cleanupThread' , 'thread' : thread } ) ;
917
933
return 0 ;
@@ -924,7 +940,7 @@ var LibraryPThread = {
924
940
// runtime and launched main()), assist pthreads in performing operations
925
941
// that they need to access the Emscripten main runtime for.
926
942
if ( ! ENVIRONMENT_IS_PTHREAD ) _emscripten_main_thread_process_queued_calls ( ) ;
927
- _emscripten_futex_wait ( thread + { { { C_STRUCTS . pthread . threadStatus } } } , threadStatus , ENVIRONMENT_IS_PTHREAD ? 100 : 1 ) ;
943
+ _emscripten_futex_wait ( thread + { { { C_STRUCTS . pthread . detach_state } } } , detach_state , ENVIRONMENT_IS_PTHREAD ? 100 : 1 ) ;
928
944
}
929
945
} ,
930
946
@@ -977,7 +993,8 @@ var LibraryPThread = {
977
993
err ( 'pthread_cancel attempted on thread ' + thread + ', which does not point to a valid thread, or does not exist anymore!' ) ;
978
994
return { { { cDefine ( 'ESRCH' ) } } } ;
979
995
}
980
- Atomics . compareExchange ( HEAPU32 , ( thread + { { { C_STRUCTS . pthread . threadStatus } } } ) >> 2 , 0 , 2 ) ; // Signal the thread that it needs to cancel itself.
996
+ // Signal the thread that it needs to cancel itself.
997
+ Atomics . store ( HEAPU32 , ( thread + { { { C_STRUCTS . pthread . cancel } } } ) >> 2 , 1 ) ;
981
998
if ( ! ENVIRONMENT_IS_PTHREAD ) cancelThread ( thread ) ;
982
999
else postMessage ( { 'cmd' : 'cancelThread' , 'thread' : thread } ) ;
983
1000
return 0 ;
0 commit comments