@@ -31,7 +31,7 @@ use crate::{
3131 } ,
3232 capture_future:: { self , CaptureFuture } ,
3333 event:: { Event , EventListener } ,
34- id:: { BackendJobId , FunctionId , LocalTaskId , TraitTypeId , TRANSIENT_TASK_BIT } ,
34+ id:: { BackendJobId , ExecutionId , FunctionId , LocalTaskId , TraitTypeId , TRANSIENT_TASK_BIT } ,
3535 id_factory:: IdFactoryWithReuse ,
3636 magic_any:: MagicAny ,
3737 raw_vc:: { CellId , RawVc } ,
@@ -41,10 +41,11 @@ use crate::{
4141 task_statistics:: TaskStatisticsApi ,
4242 trace:: TraceRawVcs ,
4343 trait_helpers:: get_trait_method,
44- util:: StaticOrArc ,
44+ util:: { IdFactory , StaticOrArc } ,
4545 vc:: ReadVcFuture ,
46- Completion , InvalidationReason , InvalidationReasonSet , ReadCellOptions , ResolvedVc ,
47- SharedReference , TaskId , TaskIdSet , ValueTypeId , Vc , VcRead , VcValueTrait , VcValueType ,
46+ Completion , InvalidationReason , InvalidationReasonSet , OutputContent , ReadCellOptions ,
47+ ResolvedVc , SharedReference , TaskId , TaskIdSet , ValueTypeId , Vc , VcRead , VcValueTrait ,
48+ VcValueType ,
4849} ;
4950
5051pub trait TurboTasksCallApi : Sync + Send {
@@ -139,7 +140,7 @@ pub trait TurboTasksApi: TurboTasksCallApi + Sync + Send {
139140 /// `OperationVc`s, which should never be local tasks.
140141 fn try_read_local_output (
141142 & self ,
142- parent_task_id : TaskId ,
143+ execution_id : ExecutionId ,
143144 local_task_id : LocalTaskId ,
144145 ) -> Result < Result < RawVc , EventListener > > ;
145146
@@ -347,6 +348,7 @@ pub struct TurboTasks<B: Backend + 'static> {
347348 backend : B ,
348349 task_id_factory : IdFactoryWithReuse < TaskId > ,
349350 transient_task_id_factory : IdFactoryWithReuse < TaskId > ,
351+ execution_id_factory : IdFactory < ExecutionId > ,
350352 stopped : AtomicBool ,
351353 currently_scheduled_tasks : AtomicUsize ,
352354 currently_scheduled_foreground_jobs : AtomicUsize ,
@@ -371,6 +373,7 @@ pub struct TurboTasks<B: Backend + 'static> {
371373/// - The backend is aware of.
372374struct CurrentTaskState {
373375 task_id : TaskId ,
376+ execution_id : ExecutionId ,
374377
375378 /// Affected tasks, that are tracked during task execution. These tasks will
376379 /// be invalidated when the execution finishes or before reading a cell
@@ -397,9 +400,14 @@ struct CurrentTaskState {
397400}
398401
399402impl CurrentTaskState {
400- fn new ( task_id : TaskId , backend_state : Box < dyn Any + Send + Sync > ) -> Self {
403+ fn new (
404+ task_id : TaskId ,
405+ execution_id : ExecutionId ,
406+ backend_state : Box < dyn Any + Send + Sync > ,
407+ ) -> Self {
401408 Self {
402409 task_id,
410+ execution_id,
403411 tasks_to_notify : Vec :: new ( ) ,
404412 stateful : false ,
405413 cell_counters : Some ( AutoMap :: default ( ) ) ,
@@ -409,10 +417,11 @@ impl CurrentTaskState {
409417 }
410418 }
411419
412- fn assert_task_id ( & self , expected_task_id : TaskId ) {
413- if self . task_id != expected_task_id {
414- unimplemented ! (
415- "Local tasks can currently only be scheduled/awaited within their parent task"
420+ fn assert_execution_id ( & self , expected_execution_id : ExecutionId ) {
421+ if self . execution_id != expected_execution_id {
422+ panic ! (
423+ "Local tasks can only be scheduled/awaited within the same execution of the \
424+ parent task that created them"
416425 ) ;
417426 }
418427 }
@@ -458,11 +467,13 @@ impl<B: Backend + 'static> TurboTasks<B> {
458467 ) ;
459468 let transient_task_id_factory =
460469 IdFactoryWithReuse :: new ( TaskId :: try_from ( TRANSIENT_TASK_BIT ) . unwrap ( ) , TaskId :: MAX ) ;
470+ let execution_id_factory = IdFactory :: new ( ExecutionId :: MIN , ExecutionId :: MAX ) ;
461471 let this = Arc :: new_cyclic ( |this| Self {
462472 this : this. clone ( ) ,
463473 backend,
464474 task_id_factory,
465475 transient_task_id_factory,
476+ execution_id_factory,
466477 stopped : AtomicBool :: new ( false ) ,
467478 currently_scheduled_tasks : AtomicUsize :: new ( 0 ) ,
468479 currently_scheduled_background_jobs : AtomicUsize :: new ( 0 ) ,
@@ -644,8 +655,11 @@ impl<B: Backend + 'static> TurboTasks<B> {
644655 let mut schedule_again = true ;
645656 while schedule_again {
646657 let backend_state = this. backend . new_task_state ( task_id) ;
658+ // it's okay for execution ids to overflow and wrap, they're just used for an assert
659+ let execution_id = this. execution_id_factory . wrapping_get ( ) ;
647660 let current_task_state = Arc :: new ( RwLock :: new ( CurrentTaskState :: new (
648661 task_id,
662+ execution_id,
649663 Box :: new ( backend_state) ,
650664 ) ) ) ;
651665 let single_execution_future = async {
@@ -722,22 +736,31 @@ impl<B: Backend + 'static> TurboTasks<B> {
722736 & self ,
723737 ty : LocalTaskType ,
724738 // if this is a `LocalTaskType::Resolve*`, we may spawn another task with this persistence,
725- // if this is a `LocalTaskType::Native`, persistence is unused (there's no caching).
739+ // if this is a `LocalTaskType::Native`, persistence is unused.
740+ //
741+ // TODO: In the rare case that we're crossing a transient->persistent boundary, we should
742+ // force `LocalTaskType::Native` to be spawned as real tasks, so that any cells they create
743+ // have the correct persistence. This is not an issue for resolution stub task, as they
744+ // don't end up owning any cells.
726745 persistence : TaskPersistence ,
727746 ) -> RawVc {
728- use crate :: OutputContent ;
729-
730747 let ty = Arc :: new ( ty) ;
731- let ( global_task_state, local_task_id, parent_task_id) = CURRENT_TASK_STATE . with ( |gts| {
732- let mut gts_write = gts. write ( ) . unwrap ( ) ;
733- let local_task_id = gts_write. create_local_task ( LocalTask :: Scheduled {
734- done_event : Event :: new ( {
735- let ty = Arc :: clone ( & ty) ;
736- move || format ! ( "LocalTask({})::done_event" , ty)
737- } ) ,
748+ let ( global_task_state, parent_task_id, execution_id, local_task_id) = CURRENT_TASK_STATE
749+ . with ( |gts| {
750+ let mut gts_write = gts. write ( ) . unwrap ( ) ;
751+ let local_task_id = gts_write. create_local_task ( LocalTask :: Scheduled {
752+ done_event : Event :: new ( {
753+ let ty = Arc :: clone ( & ty) ;
754+ move || format ! ( "LocalTask({})::done_event" , ty)
755+ } ) ,
756+ } ) ;
757+ (
758+ Arc :: clone ( gts) ,
759+ gts_write. task_id ,
760+ gts_write. execution_id ,
761+ local_task_id,
762+ )
738763 } ) ;
739- ( Arc :: clone ( gts) , local_task_id, gts_write. task_id )
740- } ) ;
741764
742765 #[ cfg( feature = "tokio_tracing" ) ]
743766 let description = format ! (
@@ -799,7 +822,7 @@ impl<B: Backend + 'static> TurboTasks<B> {
799822 #[ cfg( not( feature = "tokio_tracing" ) ) ]
800823 tokio:: task:: spawn ( future) ;
801824
802- RawVc :: LocalOutput ( parent_task_id, persistence, local_task_id)
825+ RawVc :: LocalOutput ( parent_task_id, persistence, execution_id , local_task_id)
803826 }
804827
805828 fn begin_primary_job ( & self ) {
@@ -1277,17 +1300,17 @@ impl<B: Backend + 'static> TurboTasksApi for TurboTasks<B> {
12771300
12781301 fn try_read_local_output (
12791302 & self ,
1280- parent_task_id : TaskId ,
1303+ execution_id : ExecutionId ,
12811304 local_task_id : LocalTaskId ,
12821305 ) -> Result < Result < RawVc , EventListener > > {
12831306 CURRENT_TASK_STATE . with ( |gts| {
12841307 let gts_read = gts. read ( ) . unwrap ( ) ;
12851308
1286- // Local Vcs are local to their parent task, and do not exist outside of it. This is
1287- // weakly enforced at compile time using the `NonLocalValue` marker trait. This
1288- // assertion exists to handle any potential escapes that the compile-time checks cannot
1289- // capture.
1290- gts_read. assert_task_id ( parent_task_id ) ;
1309+ // Local Vcs are local to their parent task's current execution , and do not exist
1310+ // outside of it. This is weakly enforced at compile time using the `NonLocalValue`
1311+ // marker trait. This assertion exists to handle any potential escapes that the
1312+ // compile-time checks cannot capture.
1313+ gts_read. assert_execution_id ( execution_id ) ;
12911314
12921315 match gts_read. get_local_task ( local_task_id) {
12931316 LocalTask :: Scheduled { done_event } => Ok ( Err ( done_event. listen ( ) ) ) ,
@@ -1632,13 +1655,15 @@ pub fn turbo_tasks_future_scope<T>(
16321655pub fn with_turbo_tasks_for_testing < T > (
16331656 tt : Arc < dyn TurboTasksApi > ,
16341657 current_task : TaskId ,
1658+ execution_id : ExecutionId ,
16351659 f : impl Future < Output = T > ,
16361660) -> impl Future < Output = T > {
16371661 TURBO_TASKS . scope (
16381662 tt,
16391663 CURRENT_TASK_STATE . scope (
16401664 Arc :: new ( RwLock :: new ( CurrentTaskState :: new (
16411665 current_task,
1666+ execution_id,
16421667 Box :: new ( ( ) ) ,
16431668 ) ) ) ,
16441669 f,
@@ -1969,11 +1994,11 @@ pub fn find_cell_by_type(ty: ValueTypeId) -> CurrentCellRef {
19691994
19701995pub ( crate ) async fn read_local_output (
19711996 this : & dyn TurboTasksApi ,
1972- parent_task_id : TaskId ,
1997+ execution_id : ExecutionId ,
19731998 local_task_id : LocalTaskId ,
19741999) -> Result < RawVc > {
19752000 loop {
1976- match this. try_read_local_output ( parent_task_id , local_task_id) ? {
2001+ match this. try_read_local_output ( execution_id , local_task_id) ? {
19772002 Ok ( raw_vc) => return Ok ( raw_vc) ,
19782003 Err ( event_listener) => event_listener. await ,
19792004 }
0 commit comments