77var LibraryPThread = {
88 $PThread__postset : 'if (!ENVIRONMENT_IS_PTHREAD) PThread.initMainThread();' ,
99 $PThread__deps : [ '_emscripten_thread_init' ,
10- '$killThread' ,
1110 '$cancelThread' , '$cleanupThread' , '$zeroMemory' ,
1211 '_emscripten_thread_free_data' ,
1312 'exit' ,
@@ -96,7 +95,7 @@ var LibraryPThread = {
9695 for ( var t in PThread . pthreads ) {
9796 var pthread = PThread . pthreads [ t ] ;
9897 if ( pthread && pthread . worker ) {
99- PThread . returnWorkerToPool ( pthread . worker ) ;
98+ cleanupThread ( t , true ) ;
10099 }
101100 }
102101
@@ -117,17 +116,21 @@ var LibraryPThread = {
117116 }
118117 PThread . unusedWorkers = [ ] ;
119118 } ,
120- returnWorkerToPool : function ( worker ) {
119+ returnWorkerToPool : function ( worker , terminate ) {
121120 // We don't want to run main thread queued calls here, since we are doing
122121 // some operations that leave the worker queue in an invalid state until
123122 // we are completely done (it would be bad if free() ends up calling a
124123 // queued pthread_create which looks at the global data structures we are
125124 // modifying).
126125 PThread . runWithoutMainThreadQueuedCalls ( function ( ) {
127126 delete PThread . pthreads [ worker . pthread . threadInfoStruct ] ;
128- // Note: worker is intentionally not terminated so the pool can
129- // dynamically grow.
130- PThread . unusedWorkers . push ( worker ) ;
127+ if ( terminate ) {
128+ worker . terminate ( ) ;
129+ } else {
130+ // No termination needed? Return it to the worker pool as an
131+ // unused worker so the pool can dynamically grow.
132+ PThread . unusedWorkers . push ( worker ) ;
133+ }
131134 PThread . runningWorkers . splice ( PThread . runningWorkers . indexOf ( worker ) , 1 ) ;
132135 // Not a running Worker anymore
133136 __emscripten_thread_free_data ( worker . pthread . threadInfoStruct ) ;
@@ -214,9 +217,7 @@ var LibraryPThread = {
214217 } else if ( cmd === 'spawnThread' ) {
215218 spawnThread ( d ) ;
216219 } else if ( cmd === 'cleanupThread' ) {
217- cleanupThread ( d [ 'thread' ] ) ;
218- } else if ( cmd === 'killThread' ) {
219- killThread ( d [ 'thread' ] ) ;
220+ cleanupThread ( d [ 'thread' ] , d [ 'terminate' ] ) ;
220221 } else if ( cmd === 'cancelThread' ) {
221222 cancelThread ( d [ 'thread' ] ) ;
222223 } else if ( cmd === 'loaded' ) {
@@ -387,59 +388,23 @@ var LibraryPThread = {
387388 }
388389 } ,
389390
390- $killThread__deps: [ '_emscripten_thread_free_data' ] ,
391- $killThread : function ( pthread_ptr ) {
392- #if PTHREADS_DEBUG
393- err ( 'killThread 0x' + pthread_ptr . toString ( 16 ) ) ;
394- #endif
395- #if ASSERTIONS
396- assert ( ! ENVIRONMENT_IS_PTHREAD , 'Internal Error! killThread() can only ever be called from main application thread!' ) ;
397- assert ( pthread_ptr , 'Internal Error! Null pthread_ptr in killThread!' ) ;
398- #endif
399- { { { makeSetValue ( 'pthread_ptr' , C_STRUCTS . pthread . self , 0 , 'i32' ) } } } ;
400- var pthread = PThread . pthreads [ pthread_ptr ] ;
401- delete PThread . pthreads [ pthread_ptr ] ;
402- pthread . worker . terminate ( ) ;
403- __emscripten_thread_free_data ( pthread_ptr ) ;
404- // The worker was completely nuked (not just the pthread execution it was hosting), so remove it from running workers
405- // but don't put it back to the pool.
406- PThread . runningWorkers . splice ( PThread . runningWorkers . indexOf ( pthread . worker ) , 1 ) ; // Not a running Worker anymore.
407- pthread . worker . pthread = undefined ;
408- } ,
409-
410391 __emscripten_thread_cleanup: function ( thread ) {
411392 // Called when a thread needs to be cleaned up so it can be reused.
412393 // A thread is considered reusable when it either returns from its
413394 // entry point, calls pthread_exit, or acts upon a cancellation.
414395 // Detached threads are responsible for calling this themselves,
415396 // otherwise pthread_join is responsible for calling this.
416- if ( ! ENVIRONMENT_IS_PTHREAD ) cleanupThread ( thread ) ;
417- else postMessage ( { 'cmd' : 'cleanupThread' , 'thread' : thread } ) ;
397+ if ( ! ENVIRONMENT_IS_PTHREAD ) cleanupThread ( thread , false ) ;
398+ else postMessage ( { 'cmd' : 'cleanupThread' , 'thread' : thread , 'terminate' : false } ) ;
418399 } ,
419400
420- $cleanupThread : function ( pthread_ptr ) {
401+ $cleanupThread : function ( pthread_ptr , terminate ) {
421402#if ASSERTIONS
422403 assert ( ! ENVIRONMENT_IS_PTHREAD , 'Internal Error! cleanupThread() can only ever be called from main application thread!' ) ;
423404 assert ( pthread_ptr , 'Internal Error! Null pthread_ptr in cleanupThread!' ) ;
424405#endif
425406 var pthread = PThread . pthreads [ pthread_ptr ] ;
426- // If pthread has been removed from this map this also means that pthread_ptr points
427- // to already freed data. Such situation may occur in following circumstance:
428- // Joining thread from non-main browser thread (this also includes thread running main()
429- // when compiled with `PROXY_TO_PTHREAD`) - in such situation it may happen that following
430- // code flow occur (MB - Main Browser Thread, S1, S2 - Worker Threads):
431- // S2: thread ends, 'exit' message is sent to MB
432- // S1: calls pthread_join(S2), this causes:
433- // a. S2 is marked as detached,
434- // b. 'cleanupThread' message is sent to MB.
435- // MB: handles 'exit' message, as thread is detached, so returnWorkerToPool()
436- // is called and all thread related structs are freed/released.
437- // MB: handles 'cleanupThread' message which calls this function.
438- if ( pthread ) {
439- { { { makeSetValue ( 'pthread_ptr' , C_STRUCTS . pthread . self , 0 , 'i32' ) } } } ;
440- var worker = pthread . worker ;
441- PThread . returnWorkerToPool ( worker ) ;
442- }
407+ if ( pthread ) PThread . returnWorkerToPool ( pthread . worker , terminate ) ;
443408 } ,
444409
445410 $registerTlsInit : function ( tlsInitFunc , moduleExports , metadata ) {
@@ -489,7 +454,7 @@ var LibraryPThread = {
489454 assert ( pthread_ptr , 'Internal Error! Null pthread_ptr in cancelThread!' ) ;
490455#endif
491456 var pthread = PThread . pthreads [ pthread_ptr ] ;
492- pthread . worker . postMessage ( { 'cmd' : 'cancel' } ) ;
457+ if ( pthread ) pthread . worker . postMessage ( { 'cmd' : 'cancel' } ) ;
493458 } ,
494459
495460 $spawnThread : function ( threadParams ) {
@@ -768,17 +733,17 @@ var LibraryPThread = {
768733 err ( 'pthread_kill attempted on a null thread pointer!' ) ;
769734 return { { { cDefine ( 'ESRCH' ) } } } ;
770735 }
771- var self = { { { makeGetValue ( 'thread' , C_STRUCTS . pthread . self , 'i32' ) } } } ;
772- if ( self !== thread ) {
736+ var tid = { { { makeGetValue ( 'thread' , C_STRUCTS . pthread . tid , 'i32' ) } } } ;
737+ if ( ! tid ) {
773738 err ( 'pthread_kill attempted on thread 0x' + thread . toString ( 16 ) + ', which does not point to a valid thread, or does not exist anymore!' ) ;
774739 return { { { cDefine ( 'ESRCH' ) } } } ;
775740 }
776741 if ( signal === { { { cDefine ( 'SIGCANCEL' ) } } } ) { // Used by pthread_cancel in musl
777742 if ( ! ENVIRONMENT_IS_PTHREAD ) cancelThread ( thread ) ;
778743 else postMessage ( { 'cmd' : 'cancelThread' , 'thread' : thread } ) ;
779744 } else if ( signal != 0 ) {
780- if ( ! ENVIRONMENT_IS_PTHREAD ) killThread ( thread ) ;
781- else postMessage ( { 'cmd' : 'killThread ' , 'thread' : thread } ) ;
745+ if ( ! ENVIRONMENT_IS_PTHREAD ) cleanupThread ( thread , true ) ;
746+ else postMessage ( { 'cmd' : 'cleanupThread ' , 'thread' : thread , 'terminate' : true } ) ;
782747 }
783748 return 0 ;
784749 } ,
0 commit comments