7
7
var LibraryPThread = {
8
8
$PThread__postset : 'if (!ENVIRONMENT_IS_PTHREAD) PThread.initMainThread();' ,
9
9
$PThread__deps : [ '_emscripten_thread_init' ,
10
- '$killThread' ,
11
10
'$cancelThread' , '$cleanupThread' , '$zeroMemory' ,
12
11
'_emscripten_thread_free_data' ,
13
12
'exit' ,
@@ -96,7 +95,7 @@ var LibraryPThread = {
96
95
for ( var t in PThread . pthreads ) {
97
96
var pthread = PThread . pthreads [ t ] ;
98
97
if ( pthread && pthread . worker ) {
99
- PThread . returnWorkerToPool ( pthread . worker ) ;
98
+ cleanupThread ( t , true ) ;
100
99
}
101
100
}
102
101
@@ -117,17 +116,21 @@ var LibraryPThread = {
117
116
}
118
117
PThread . unusedWorkers = [ ] ;
119
118
} ,
120
- returnWorkerToPool : function ( worker ) {
119
+ returnWorkerToPool : function ( worker , terminate ) {
121
120
// We don't want to run main thread queued calls here, since we are doing
122
121
// some operations that leave the worker queue in an invalid state until
123
122
// we are completely done (it would be bad if free() ends up calling a
124
123
// queued pthread_create which looks at the global data structures we are
125
124
// modifying).
126
125
PThread . runWithoutMainThreadQueuedCalls ( function ( ) {
127
126
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
+ }
131
134
PThread . runningWorkers . splice ( PThread . runningWorkers . indexOf ( worker ) , 1 ) ;
132
135
// Not a running Worker anymore
133
136
__emscripten_thread_free_data ( worker . pthread . threadInfoStruct ) ;
@@ -214,9 +217,7 @@ var LibraryPThread = {
214
217
} else if ( cmd === 'spawnThread' ) {
215
218
spawnThread ( d ) ;
216
219
} else if ( cmd === 'cleanupThread' ) {
217
- cleanupThread ( d [ 'thread' ] ) ;
218
- } else if ( cmd === 'killThread' ) {
219
- killThread ( d [ 'thread' ] ) ;
220
+ cleanupThread ( d [ 'thread' ] , d [ 'terminate' ] ) ;
220
221
} else if ( cmd === 'cancelThread' ) {
221
222
cancelThread ( d [ 'thread' ] ) ;
222
223
} else if ( cmd === 'loaded' ) {
@@ -387,59 +388,23 @@ var LibraryPThread = {
387
388
}
388
389
} ,
389
390
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
-
410
391
__emscripten_thread_cleanup: function ( thread ) {
411
392
// Called when a thread needs to be cleaned up so it can be reused.
412
393
// A thread is considered reusable when it either returns from its
413
394
// entry point, calls pthread_exit, or acts upon a cancellation.
414
395
// Detached threads are responsible for calling this themselves,
415
396
// 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 } ) ;
418
399
} ,
419
400
420
- $cleanupThread : function ( pthread_ptr ) {
401
+ $cleanupThread : function ( pthread_ptr , terminate ) {
421
402
#if ASSERTIONS
422
403
assert ( ! ENVIRONMENT_IS_PTHREAD , 'Internal Error! cleanupThread() can only ever be called from main application thread!' ) ;
423
404
assert ( pthread_ptr , 'Internal Error! Null pthread_ptr in cleanupThread!' ) ;
424
405
#endif
425
406
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 ) ;
443
408
} ,
444
409
445
410
$registerTlsInit : function ( tlsInitFunc , moduleExports , metadata ) {
@@ -489,7 +454,7 @@ var LibraryPThread = {
489
454
assert ( pthread_ptr , 'Internal Error! Null pthread_ptr in cancelThread!' ) ;
490
455
#endif
491
456
var pthread = PThread . pthreads [ pthread_ptr ] ;
492
- pthread . worker . postMessage ( { 'cmd' : 'cancel' } ) ;
457
+ if ( pthread ) pthread . worker . postMessage ( { 'cmd' : 'cancel' } ) ;
493
458
} ,
494
459
495
460
$spawnThread : function ( threadParams ) {
@@ -768,17 +733,17 @@ var LibraryPThread = {
768
733
err ( 'pthread_kill attempted on a null thread pointer!' ) ;
769
734
return { { { cDefine ( 'ESRCH' ) } } } ;
770
735
}
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 ) {
773
738
err ( 'pthread_kill attempted on thread 0x' + thread . toString ( 16 ) + ', which does not point to a valid thread, or does not exist anymore!' ) ;
774
739
return { { { cDefine ( 'ESRCH' ) } } } ;
775
740
}
776
741
if ( signal === { { { cDefine ( 'SIGCANCEL' ) } } } ) { // Used by pthread_cancel in musl
777
742
if ( ! ENVIRONMENT_IS_PTHREAD ) cancelThread ( thread ) ;
778
743
else postMessage ( { 'cmd' : 'cancelThread' , 'thread' : thread } ) ;
779
744
} 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 } ) ;
782
747
}
783
748
return 0 ;
784
749
} ,
0 commit comments