@@ -598,7 +598,7 @@ var LibraryPThread = {
598
598
// Pass the thread address to the native code where they stored in wasm
599
599
// globals which act as a form of TLS. Global constructors trying
600
600
// to access this value will read the wrong value, but that is UB anyway.
601
- __emscripten_thread_init ( tb , /*isMainBrowserThread=*/ ! ENVIRONMENT_IS_WORKER , /*isMainRuntimeThread=*/ 1 ) ;
601
+ __emscripten_thread_init ( tb , /*isMainBrowserThread=*/ ! ENVIRONMENT_IS_WORKER , /*isMainRuntimeThread=*/ 1 , /*canBlock=*/ ! ENVIRONMENT_IS_WEB ) ;
602
602
#if ASSERTIONS
603
603
PThread . mainRuntimeThread = true ;
604
604
// Verify that this native symbol used by futex_wait/wake is exported correctly.
@@ -843,134 +843,112 @@ var LibraryPThread = {
843
843
} ,
844
844
845
845
// Returns 0 on success, or one of the values -ETIMEDOUT, -EWOULDBLOCK or -EINVAL on error.
846
- emscripten_futex_wait__deps : [ 'emscripten_main_thread_process_queued_calls' ] ,
847
- emscripten_futex_wait : function ( addr , val , timeout ) {
848
- if ( addr <= 0 || addr > HEAP8 . length || addr & 3 != 0 ) return - { { { cDefine ( 'EINVAL' ) } } } ;
849
- // We can do a normal blocking wait anywhere but on the main browser thread.
850
- if ( ! ENVIRONMENT_IS_WEB ) {
851
- #if PTHREADS_PROFILING
852
- PThread . setThreadStatusConditional ( _pthread_self ( ) , { { { cDefine ( 'EM_THREAD_STATUS_RUNNING' ) } } } , { { { cDefine ( 'EM_THREAD_STATUS_WAITFUTEX' ) } } } ) ;
853
- #endif
854
- var ret = Atomics . wait ( HEAP32 , addr >> 2 , val , timeout ) ;
855
- #if PTHREADS_PROFILING
856
- PThread . setThreadStatusConditional ( _pthread_self ( ) , { { { cDefine ( 'EM_THREAD_STATUS_WAITFUTEX' ) } } } , { { { cDefine ( 'EM_THREAD_STATUS_RUNNING' ) } } } ) ;
857
- #endif
858
- if ( ret === 'timed-out' ) return - { { { cDefine ( 'ETIMEDOUT' ) } } } ;
859
- if ( ret === 'not-equal' ) return - { { { cDefine ( 'EWOULDBLOCK' ) } } } ;
860
- if ( ret === 'ok' ) return 0 ;
861
- throw 'Atomics.wait returned an unexpected value ' + ret ;
862
- } else {
863
- // First, check if the value is correct for us to wait on.
864
- if ( Atomics . load ( HEAP32 , addr >> 2 ) != val ) {
865
- return - { { { cDefine ( 'EWOULDBLOCK' ) } } } ;
866
- }
867
-
868
- // Atomics.wait is not available in the main browser thread, so simulate it via busy spinning.
869
- var tNow = performance . now ( ) ;
870
- var tEnd = tNow + timeout ;
871
-
872
- #if PTHREADS_PROFILING
873
- PThread . setThreadStatusConditional ( _pthread_self ( ) , { { { cDefine ( 'EM_THREAD_STATUS_RUNNING' ) } } } , { { { cDefine ( 'EM_THREAD_STATUS_WAITFUTEX' ) } } } ) ;
874
- #endif
875
- // Register globally which address the main thread is simulating to be
876
- // waiting on. When zero, the main thread is not waiting on anything, and on
877
- // nonzero, the contents of the address pointed by __emscripten_main_thread_futex
878
- // tell which address the main thread is simulating its wait on.
879
- // We need to be careful of recursion here: If we wait on a futex, and
880
- // then call _emscripten_main_thread_process_queued_calls() below, that
881
- // will call code that takes the proxying mutex - which can once more
882
- // reach this code in a nested call. To avoid interference between the
883
- // two (there is just a single __emscripten_main_thread_futex at a time), unmark
884
- // ourselves before calling the potentially-recursive call. See below for
885
- // how we handle the case of our futex being notified during the time in
886
- // between when we are not set as the value of __emscripten_main_thread_futex.
887
- var lastAddr = Atomics . exchange ( HEAP32 , __emscripten_main_thread_futex >> 2 , addr ) ;
846
+ _emscripten_futex_wait_non_blocking__deps : [ 'emscripten_main_thread_process_queued_calls' ] ,
847
+ _emscripten_futex_wait_non_blocking : function ( addr , val , timeout ) {
888
848
#if ASSERTIONS
889
- // We must not have already been waiting.
890
- assert ( lastAddr == 0 ) ;
891
- #endif
892
-
893
- while ( 1 ) {
894
- // Check for a timeout.
895
- tNow = performance . now ( ) ;
896
- if ( tNow > tEnd ) {
897
- #if PTHREADS_PROFILING
898
- PThread . setThreadStatusConditional ( _pthread_self ( ) , { { { cDefine ( 'EM_THREAD_STATUS_RUNNING' ) } } } , { { { cDefine ( 'EM_THREAD_STATUS_WAITFUTEX' ) } } } ) ;
849
+ // Should only be called from the main web thread where atomics.wait is not allowed.
850
+ assert ( ENVIRONMENT_IS_WEB ) ;
851
+ #endif
852
+
853
+ // Atomics.wait is not available in the main browser thread, so simulate it via busy spinning.
854
+ var tNow = performance . now ( ) ;
855
+ var tEnd = tNow + timeout ;
856
+
857
+ // Register globally which address the main thread is simulating to be
858
+ // waiting on. When zero, the main thread is not waiting on anything, and on
859
+ // nonzero, the contents of the address pointed by __emscripten_main_thread_futex
860
+ // tell which address the main thread is simulating its wait on.
861
+ // We need to be careful of recursion here: If we wait on a futex, and
862
+ // then call _emscripten_main_thread_process_queued_calls() below, that
863
+ // will call code that takes the proxying mutex - which can once more
864
+ // reach this code in a nested call. To avoid interference between the
865
+ // two (there is just a single __emscripten_main_thread_futex at a time), unmark
866
+ // ourselves before calling the potentially-recursive call. See below for
867
+ // how we handle the case of our futex being notified during the time in
868
+ // between when we are not set as the value of __emscripten_main_thread_futex.
869
+ #if ASSERTIONS
870
+ assert ( __emscripten_main_thread_futex > 0 ) ;
899
871
#endif
900
- // We timed out, so stop marking ourselves as waiting.
901
- lastAddr = Atomics . exchange ( HEAP32 , __emscripten_main_thread_futex >> 2 , 0 ) ;
872
+ var lastAddr = Atomics . exchange ( HEAP32 , __emscripten_main_thread_futex >> 2 , addr ) ;
902
873
#if ASSERTIONS
903
- // The current value must have been our address which we set, or
904
- // in a race it was set to 0 which means another thread just allowed
905
- // us to run, but (tragically) that happened just a bit too late.
906
- assert ( lastAddr == addr || lastAddr == 0 ) ;
874
+ // We must not have already been waiting.
875
+ assert ( lastAddr == 0 ) ;
907
876
#endif
908
- return - { { { cDefine ( 'ETIMEDOUT' ) } } } ;
909
- }
910
- // We are performing a blocking loop here, so we must handle proxied
911
- // events from pthreads, to avoid deadlocks.
912
- // Note that we have to do so carefully, as we may take a lock while
913
- // doing so, which can recurse into this function; stop marking
914
- // ourselves as waiting while we do so.
877
+
878
+ while ( 1 ) {
879
+ // Check for a timeout.
880
+ tNow = performance . now ( ) ;
881
+ if ( tNow > tEnd ) {
882
+ // We timed out, so stop marking ourselves as waiting.
915
883
lastAddr = Atomics . exchange ( HEAP32 , __emscripten_main_thread_futex >> 2 , 0 ) ;
916
884
#if ASSERTIONS
885
+ // The current value must have been our address which we set, or
886
+ // in a race it was set to 0 which means another thread just allowed
887
+ // us to run, but (tragically) that happened just a bit too late.
917
888
assert ( lastAddr == addr || lastAddr == 0 ) ;
918
889
#endif
919
- if ( lastAddr == 0 ) {
920
- // We were told to stop waiting, so stop.
921
- break ;
922
- }
923
- _emscripten_main_thread_process_queued_calls ( ) ;
924
-
925
- // Check the value, as if we were starting the futex all over again.
926
- // This handles the following case:
927
- //
928
- // * wait on futex A
929
- // * recurse into emscripten_main_thread_process_queued_calls(),
930
- // which waits on futex B. that sets the __emscripten_main_thread_futex address to
931
- // futex B, and there is no longer any mention of futex A.
932
- // * a worker is done with futex A. it checks __emscripten_main_thread_futex but does
933
- // not see A, so it does nothing special for the main thread.
934
- // * a worker is done with futex B. it flips mainThreadMutex from B
935
- // to 0, ending the wait on futex B.
936
- // * we return to the wait on futex A. __emscripten_main_thread_futex is 0, but that
937
- // is because of futex B being done - we can't tell from
938
- // __emscripten_main_thread_futex whether A is done or not. therefore, check the
939
- // memory value of the futex.
940
- //
941
- // That case motivates the design here. Given that, checking the memory
942
- // address is also necessary for other reasons: we unset and re-set our
943
- // address in __emscripten_main_thread_futex around calls to
944
- // emscripten_main_thread_process_queued_calls(), and a worker could
945
- // attempt to wake us up right before/after such times.
946
- //
947
- // Note that checking the memory value of the futex is valid to do: we
948
- // could easily have been delayed (relative to the worker holding on
949
- // to futex A), which means we could be starting all of our work at the
950
- // later time when there is no need to block. The only "odd" thing is
951
- // that we may have caused side effects in that "delay" time. But the
952
- // only side effects we can have are to call
953
- // emscripten_main_thread_process_queued_calls(). That is always ok to
954
- // do on the main thread (it's why it is ok for us to call it in the
955
- // middle of this function, and elsewhere). So if we check the value
956
- // here and return, it's the same is if what happened on the main thread
957
- // was the same as calling emscripten_main_thread_process_queued_calls()
958
- // a few times times before calling emscripten_futex_wait().
959
- if ( Atomics . load ( HEAP32 , addr >> 2 ) != val ) {
960
- return - { { { cDefine ( 'EWOULDBLOCK' ) } } } ;
961
- }
962
-
963
- // Mark us as waiting once more, and continue the loop.
964
- lastAddr = Atomics . exchange ( HEAP32 , __emscripten_main_thread_futex >> 2 , addr ) ;
890
+ return - { { { cDefine ( 'ETIMEDOUT' ) } } } ;
891
+ }
892
+ // We are performing a blocking loop here, so we must handle proxied
893
+ // events from pthreads, to avoid deadlocks.
894
+ // Note that we have to do so carefully, as we may take a lock while
895
+ // doing so, which can recurse into this function; stop marking
896
+ // ourselves as waiting while we do so.
897
+ lastAddr = Atomics . exchange ( HEAP32 , __emscripten_main_thread_futex >> 2 , 0 ) ;
965
898
#if ASSERTIONS
966
- assert ( lastAddr == 0 ) ;
899
+ assert ( lastAddr == addr || lastAddr == 0 ) ;
967
900
#endif
901
+ if ( lastAddr == 0 ) {
902
+ // We were told to stop waiting, so stop.
903
+ break ;
968
904
}
969
- #if PTHREADS_PROFILING
970
- PThread . setThreadStatusConditional ( _pthread_self ( ) , { { { cDefine ( 'EM_THREAD_STATUS_RUNNING' ) } } } , { { { cDefine ( 'EM_THREAD_STATUS_WAITFUTEX' ) } } } ) ;
905
+ _emscripten_main_thread_process_queued_calls ( ) ;
906
+
907
+ // Check the value, as if we were starting the futex all over again.
908
+ // This handles the following case:
909
+ //
910
+ // * wait on futex A
911
+ // * recurse into emscripten_main_thread_process_queued_calls(),
912
+ // which waits on futex B. that sets the __emscripten_main_thread_futex address to
913
+ // futex B, and there is no longer any mention of futex A.
914
+ // * a worker is done with futex A. it checks __emscripten_main_thread_futex but does
915
+ // not see A, so it does nothing special for the main thread.
916
+ // * a worker is done with futex B. it flips mainThreadMutex from B
917
+ // to 0, ending the wait on futex B.
918
+ // * we return to the wait on futex A. __emscripten_main_thread_futex is 0, but that
919
+ // is because of futex B being done - we can't tell from
920
+ // __emscripten_main_thread_futex whether A is done or not. therefore, check the
921
+ // memory value of the futex.
922
+ //
923
+ // That case motivates the design here. Given that, checking the memory
924
+ // address is also necessary for other reasons: we unset and re-set our
925
+ // address in __emscripten_main_thread_futex around calls to
926
+ // emscripten_main_thread_process_queued_calls(), and a worker could
927
+ // attempt to wake us up right before/after such times.
928
+ //
929
+ // Note that checking the memory value of the futex is valid to do: we
930
+ // could easily have been delayed (relative to the worker holding on
931
+ // to futex A), which means we could be starting all of our work at the
932
+ // later time when there is no need to block. The only "odd" thing is
933
+ // that we may have caused side effects in that "delay" time. But the
934
+ // only side effects we can have are to call
935
+ // emscripten_main_thread_process_queued_calls(). That is always ok to
936
+ // do on the main thread (it's why it is ok for us to call it in the
937
+ // middle of this function, and elsewhere). So if we check the value
938
+ // here and return, it's the same is if what happened on the main thread
939
+ // was the same as calling emscripten_main_thread_process_queued_calls()
940
+ // a few times times before calling emscripten_futex_wait().
941
+ if ( Atomics . load ( HEAP32 , addr >> 2 ) != val ) {
942
+ return - { { { cDefine ( 'EWOULDBLOCK' ) } } } ;
943
+ }
944
+
945
+ // Mark us as waiting once more, and continue the loop.
946
+ lastAddr = Atomics . exchange ( HEAP32 , __emscripten_main_thread_futex >> 2 , addr ) ;
947
+ #if ASSERTIONS
948
+ assert ( lastAddr == 0 ) ;
971
949
#endif
972
- return 0 ;
973
950
}
951
+ return 0 ;
974
952
} ,
975
953
976
954
// Returns the number of threads (>= 0) woken up, or the value -EINVAL on error.
0 commit comments