@@ -40,9 +40,10 @@ use std::sync::{Arc, RwLock};
40
40
use std:: task:: Poll ;
41
41
use std:: thread:: ThreadId ;
42
42
use std:: time:: Duration ;
43
- use tokio:: sync:: mpsc;
43
+ use tokio:: sync:: { mpsc, OwnedSemaphorePermit , Semaphore } ;
44
44
use tokio:: time:: interval;
45
- use tokio_util:: sync:: CancellationToken ;
45
+ use tokio_util:: sync:: { CancellationToken , PollSemaphore } ;
46
+ use tracing:: debug;
46
47
47
48
use crate :: snapshot;
48
49
use event_worker:: events:: { EventMetadata , WorkerEventWithMetadata } ;
@@ -93,6 +94,15 @@ pub static SHOULD_USE_VERBOSE_DEPRECATED_API_WARNING: OnceCell<bool> = OnceCell:
93
94
pub static SHOULD_INCLUDE_MALLOCED_MEMORY_ON_MEMCHECK : OnceCell < bool > = OnceCell :: new ( ) ;
94
95
pub static MAYBE_DENO_VERSION : OnceCell < String > = OnceCell :: new ( ) ;
95
96
97
+ thread_local ! {
98
+ // NOTE: Suppose we have met `.await` points while initializing a
99
+ // DenoRuntime. In that case, the current v8 isolate's thread-local state can be
100
+ // corrupted by a task initializing another DenoRuntime, so we must prevent this
101
+ // with a Semaphore.
102
+
103
+ static RUNTIME_CREATION_SEM : Arc <Semaphore > = Arc :: new( Semaphore :: new( 1 ) ) ;
104
+ }
105
+
96
106
#[ ctor]
97
107
fn init_v8_platform ( ) {
98
108
set_v8_flags ( ) ;
@@ -219,6 +229,16 @@ impl<RuntimeContext> Drop for DenoRuntime<RuntimeContext> {
219
229
}
220
230
}
221
231
232
+ impl DenoRuntime < ( ) > {
233
+ pub async fn acquire ( ) -> OwnedSemaphorePermit {
234
+ RUNTIME_CREATION_SEM
235
+ . with ( |v| v. clone ( ) )
236
+ . acquire_owned ( )
237
+ . await
238
+ . unwrap ( )
239
+ }
240
+ }
241
+
222
242
impl < RuntimeContext > DenoRuntime < RuntimeContext >
223
243
where
224
244
RuntimeContext : GetRuntimeContext ,
@@ -702,7 +722,7 @@ where
702
722
let mut accumulated_cpu_time_ns = 0i64 ;
703
723
704
724
let has_inspector = self . inspector ( ) . is_some ( ) ;
705
- let mod_result_rx = unsafe {
725
+ let mut mod_result_rx = unsafe {
706
726
self . js_runtime . v8_isolate ( ) . enter ( ) ;
707
727
708
728
if has_inspector {
@@ -750,38 +770,38 @@ where
750
770
} ;
751
771
}
752
772
753
- // {
754
- // let event_loop_fut = self.run_event_loop(
755
- // name.as_deref(),
756
- // current_thread_id,
757
- // &maybe_cpu_usage_metrics_tx,
758
- // &mut accumulated_cpu_time_ns,
759
- // );
760
-
761
- // let mod_result = tokio::select! {
762
- // // Not using biased mode leads to non-determinism for relatively simple
763
- // // programs.
764
- // biased;
765
-
766
- // maybe_mod_result = &mut mod_result_rx => {
767
- // debug!("received module evaluate {:#?}", maybe_mod_result);
768
- // maybe_mod_result
769
-
770
- // }
771
-
772
- // event_loop_result = event_loop_fut => {
773
- // if let Err(err) = event_loop_result {
774
- // Err(anyhow!("event loop error while evaluating the module: {}", err))
775
- // } else {
776
- // mod_result_rx.await
777
- // }
778
- // }
779
- // };
780
-
781
- // if let Err(err) = mod_result {
782
- // return (Err(err), get_accumulated_cpu_time_ms!());
783
- // }
784
- // }
773
+ {
774
+ let event_loop_fut = self . run_event_loop (
775
+ name. as_deref ( ) ,
776
+ current_thread_id,
777
+ & maybe_cpu_usage_metrics_tx,
778
+ & mut accumulated_cpu_time_ns,
779
+ ) ;
780
+
781
+ let mod_result = tokio:: select! {
782
+ // Not using biased mode leads to non-determinism for relatively simple
783
+ // programs.
784
+ biased;
785
+
786
+ maybe_mod_result = & mut mod_result_rx => {
787
+ debug!( "received module evaluate {:#?}" , maybe_mod_result) ;
788
+ maybe_mod_result
789
+
790
+ }
791
+
792
+ event_loop_result = event_loop_fut => {
793
+ if let Err ( err) = event_loop_result {
794
+ Err ( anyhow!( "event loop error while evaluating the module: {}" , err) )
795
+ } else {
796
+ mod_result_rx. await
797
+ }
798
+ }
799
+ } ;
800
+
801
+ if let Err ( err) = mod_result {
802
+ return ( Err ( err) , get_accumulated_cpu_time_ms ! ( ) ) ;
803
+ }
804
+ }
785
805
786
806
if let Err ( err) = self
787
807
. run_event_loop (
@@ -798,10 +818,6 @@ where
798
818
) ;
799
819
}
800
820
801
- if let Err ( err) = mod_result_rx. await {
802
- return ( Err ( err) , get_accumulated_cpu_time_ms ! ( ) ) ;
803
- }
804
-
805
821
( Ok ( ( ) ) , get_accumulated_cpu_time_ms ! ( ) )
806
822
}
807
823
@@ -818,8 +834,19 @@ where
818
834
let termination_request_token = self . termination_request_token . clone ( ) ;
819
835
820
836
let mem_check_state = is_user_worker. then ( || self . mem_check . clone ( ) ) ;
837
+ let mut poll_sem = None :: < PollSemaphore > ;
821
838
822
839
poll_fn ( move |cx| {
840
+ if poll_sem. is_none ( ) {
841
+ poll_sem = Some ( RUNTIME_CREATION_SEM . with ( |v| PollSemaphore :: new ( v. clone ( ) ) ) ) ;
842
+ }
843
+
844
+ let Poll :: Ready ( Some ( _permit) ) = poll_sem. as_mut ( ) . unwrap ( ) . poll_acquire ( cx) else {
845
+ return Poll :: Pending ;
846
+ } ;
847
+
848
+ poll_sem = None ;
849
+
823
850
// INVARIANT: Only can steal current task by other threads when LIFO
824
851
// task scheduler heuristic disabled. Turning off the heuristic is
825
852
// unstable now, so it's not considered.
0 commit comments