29
29
var LibraryPThread = {
30
30
$PThread__postset : 'PThread.init();' ,
31
31
$PThread__deps : [ '_emscripten_thread_init' ,
32
- '$killThread' ,
33
32
'$cancelThread' , '$cleanupThread' , '$zeroMemory' ,
34
33
'$ptrToString' , '$spawnThread' ,
35
34
'_emscripten_thread_free_data' ,
@@ -157,7 +156,7 @@ var LibraryPThread = {
157
156
for ( var t in PThread . pthreads ) {
158
157
var pthread = PThread . pthreads [ t ] ;
159
158
if ( pthread && pthread . worker ) {
160
- PThread . returnWorkerToPool ( pthread . worker ) ;
159
+ cleanupThread ( t , true ) ;
161
160
}
162
161
}
163
162
@@ -178,17 +177,21 @@ var LibraryPThread = {
178
177
}
179
178
PThread . unusedWorkers = [ ] ;
180
179
} ,
181
- returnWorkerToPool : function ( worker ) {
180
+ returnWorkerToPool : function ( worker , terminate ) {
182
181
// We don't want to run main thread queued calls here, since we are doing
183
182
// some operations that leave the worker queue in an invalid state until
184
183
// we are completely done (it would be bad if free() ends up calling a
185
184
// queued pthread_create which looks at the global data structures we are
186
185
// modifying).
187
186
PThread . runWithoutMainThreadQueuedCalls ( function ( ) {
188
187
delete PThread . pthreads [ worker . pthread . threadInfoStruct ] ;
189
- // Note: worker is intentionally not terminated so the pool can
190
- // dynamically grow.
191
- PThread . unusedWorkers . push ( worker ) ;
188
+ if ( terminate ) {
189
+ worker . terminate ( ) ;
190
+ } else {
191
+ // No termination needed? Return it to the worker pool as an
192
+ // unused worker so the pool can dynamically grow.
193
+ PThread . unusedWorkers . push ( worker ) ;
194
+ }
192
195
PThread . runningWorkers . splice ( PThread . runningWorkers . indexOf ( worker ) , 1 ) ;
193
196
// Not a running Worker anymore
194
197
__emscripten_thread_free_data ( worker . pthread . threadInfoStruct ) ;
@@ -272,9 +275,7 @@ var LibraryPThread = {
272
275
} else if ( cmd === 'spawnThread' ) {
273
276
spawnThread ( d ) ;
274
277
} else if ( cmd === 'cleanupThread' ) {
275
- cleanupThread ( d [ 'thread' ] ) ;
276
- } else if ( cmd === 'killThread' ) {
277
- killThread ( d [ 'thread' ] ) ;
278
+ cleanupThread ( d [ 'thread' ] , d [ 'terminate' ] ) ;
278
279
} else if ( cmd === 'cancelThread' ) {
279
280
cancelThread ( d [ 'thread' ] ) ;
280
281
} else if ( cmd === 'loaded' ) {
@@ -451,59 +452,23 @@ var LibraryPThread = {
451
452
}
452
453
} ,
453
454
454
- $killThread__deps: [ '_emscripten_thread_free_data' ] ,
455
- $killThread : function ( pthread_ptr ) {
456
- #if PTHREADS_DEBUG
457
- err ( 'killThread ' + ptrToString ( pthread_ptr ) ) ;
458
- #endif
459
- #if ASSERTIONS
460
- assert ( ! ENVIRONMENT_IS_PTHREAD , 'Internal Error! killThread() can only ever be called from main application thread!' ) ;
461
- assert ( pthread_ptr , 'Internal Error! Null pthread_ptr in killThread!' ) ;
462
- #endif
463
- { { { makeSetValue ( 'pthread_ptr' , C_STRUCTS . pthread . self , 0 , 'i32' ) } } } ;
464
- var pthread = PThread . pthreads [ pthread_ptr ] ;
465
- delete PThread . pthreads [ pthread_ptr ] ;
466
- pthread . worker . terminate ( ) ;
467
- __emscripten_thread_free_data ( pthread_ptr ) ;
468
- // The worker was completely nuked (not just the pthread execution it was hosting), so remove it from running workers
469
- // but don't put it back to the pool.
470
- PThread . runningWorkers . splice ( PThread . runningWorkers . indexOf ( pthread . worker ) , 1 ) ; // Not a running Worker anymore.
471
- pthread . worker . pthread = undefined ;
472
- } ,
473
-
474
455
__emscripten_thread_cleanup: function ( thread ) {
475
456
// Called when a thread needs to be cleaned up so it can be reused.
476
457
// A thread is considered reusable when it either returns from its
477
458
// entry point, calls pthread_exit, or acts upon a cancellation.
478
459
// Detached threads are responsible for calling this themselves,
479
460
// otherwise pthread_join is responsible for calling this.
480
- if ( ! ENVIRONMENT_IS_PTHREAD ) cleanupThread ( thread ) ;
481
- else postMessage ( { 'cmd' : 'cleanupThread' , 'thread' : thread } ) ;
461
+ if ( ! ENVIRONMENT_IS_PTHREAD ) cleanupThread ( thread , false ) ;
462
+ else postMessage ( { 'cmd' : 'cleanupThread' , 'thread' : thread , 'terminate' : false } ) ;
482
463
} ,
483
464
484
- $cleanupThread : function ( pthread_ptr ) {
465
+ $cleanupThread : function ( pthread_ptr , terminate ) {
485
466
#if ASSERTIONS
486
467
assert ( ! ENVIRONMENT_IS_PTHREAD , 'Internal Error! cleanupThread() can only ever be called from main application thread!' ) ;
487
468
assert ( pthread_ptr , 'Internal Error! Null pthread_ptr in cleanupThread!' ) ;
488
469
#endif
489
470
var pthread = PThread . pthreads [ pthread_ptr ] ;
490
- // If pthread has been removed from this map this also means that pthread_ptr points
491
- // to already freed data. Such situation may occur in following circumstance:
492
- // Joining thread from non-main browser thread (this also includes thread running main()
493
- // when compiled with `PROXY_TO_PTHREAD`) - in such situation it may happen that following
494
- // code flow occur (MB - Main Browser Thread, S1, S2 - Worker Threads):
495
- // S2: thread ends, 'exit' message is sent to MB
496
- // S1: calls pthread_join(S2), this causes:
497
- // a. S2 is marked as detached,
498
- // b. 'cleanupThread' message is sent to MB.
499
- // MB: handles 'exit' message, as thread is detached, so returnWorkerToPool()
500
- // is called and all thread related structs are freed/released.
501
- // MB: handles 'cleanupThread' message which calls this function.
502
- if ( pthread ) {
503
- { { { makeSetValue ( 'pthread_ptr' , C_STRUCTS . pthread . self , 0 , 'i32' ) } } } ;
504
- var worker = pthread . worker ;
505
- PThread . returnWorkerToPool ( worker ) ;
506
- }
471
+ if ( pthread ) PThread . returnWorkerToPool ( pthread . worker , terminate ) ;
507
472
} ,
508
473
509
474
#if MAIN_MODULE
@@ -555,7 +520,7 @@ var LibraryPThread = {
555
520
assert ( pthread_ptr , 'Internal Error! Null pthread_ptr in cancelThread!' ) ;
556
521
#endif
557
522
var pthread = PThread . pthreads [ pthread_ptr ] ;
558
- pthread . worker . postMessage ( { 'cmd' : 'cancel' } ) ;
523
+ if ( pthread ) pthread . worker . postMessage ( { 'cmd' : 'cancel' } ) ;
559
524
} ,
560
525
561
526
$spawnThread : function ( threadParams ) {
@@ -842,17 +807,17 @@ var LibraryPThread = {
842
807
err ( 'pthread_kill attempted on a null thread pointer!' ) ;
843
808
return { { { cDefine ( 'ESRCH' ) } } } ;
844
809
}
845
- var self = { { { makeGetValue ( 'thread' , C_STRUCTS . pthread . self , 'i32' ) } } } ;
846
- if ( self !== thread ) {
810
+ var tid = { { { makeGetValue ( 'thread' , C_STRUCTS . pthread . tid , 'i32' ) } } } ;
811
+ if ( ! tid ) {
847
812
err ( 'pthread_kill attempted on thread ' + ptrToString ( thread ) + ', which does not point to a valid thread, or does not exist anymore!' ) ;
848
813
return { { { cDefine ( 'ESRCH' ) } } } ;
849
814
}
850
815
if ( signal === { { { cDefine ( 'SIGCANCEL' ) } } } ) { // Used by pthread_cancel in musl
851
816
if ( ! ENVIRONMENT_IS_PTHREAD ) cancelThread ( thread ) ;
852
817
else postMessage ( { 'cmd' : 'cancelThread' , 'thread' : thread } ) ;
853
818
} else if ( signal != 0 ) {
854
- if ( ! ENVIRONMENT_IS_PTHREAD ) killThread ( thread ) ;
855
- else postMessage ( { 'cmd' : 'killThread ' , 'thread' : thread } ) ;
819
+ if ( ! ENVIRONMENT_IS_PTHREAD ) cleanupThread ( thread , true ) ;
820
+ else postMessage ( { 'cmd' : 'cleanupThread ' , 'thread' : thread , 'terminate' : true } ) ;
856
821
}
857
822
return 0 ;
858
823
} ,
0 commit comments