1- use std:: { cell:: RefCell , future:: Future , marker:: PhantomData , rc:: Rc , sync :: Arc , task:: Waker } ;
1+ use std:: { cell:: RefCell , future:: Future , marker:: PhantomData , rc:: Rc , task:: Waker } ;
22
33use async_task:: { Runnable , Task } ;
44use compio_driver:: NotifyHandle ;
55use crossbeam_queue:: SegQueue ;
66use slab:: Slab ;
77
88use crate :: runtime:: scheduler:: {
9- drop_hook:: DropHook , local_queue:: LocalQueue , send_wrapper:: SendWrapper ,
9+ drop_hook:: DropHook , local_queue:: LocalQueue , raw_ref :: Own , send_wrapper:: SendWrapper ,
1010} ;
1111
1212mod drop_hook;
1313mod local_queue;
14+ mod raw_ref;
1415mod send_wrapper;
1516
1617/// A task queue consisting of a local queue and a synchronized queue.
@@ -99,7 +100,7 @@ impl TaskQueue {
99100/// A scheduler for managing and executing tasks.
100101pub ( crate ) struct Scheduler {
101102 /// Queue for scheduled tasks.
102- task_queue : Arc < TaskQueue > ,
103+ task_queue : Own < TaskQueue > ,
103104
104105 /// `Waker` of active tasks.
105106 active_tasks : Rc < RefCell < Slab < Waker > > > ,
@@ -115,7 +116,7 @@ impl Scheduler {
115116 /// Creates a new `Scheduler`.
116117 pub ( crate ) fn new ( event_interval : usize ) -> Self {
117118 Self {
118- task_queue : Arc :: new ( TaskQueue :: new ( ) ) ,
119+ task_queue : Own :: new ( TaskQueue :: new ( ) ) ,
119120 active_tasks : Rc :: new ( RefCell :: new ( Slab :: new ( ) ) ) ,
120121 event_interval,
121122 _local_marker : PhantomData ,
@@ -149,16 +150,15 @@ impl Scheduler {
149150 } ;
150151
151152 let schedule = {
152- // The schedule closure is managed by the `Waker` and may be dropped on another
153- // thread, so use `Weak` to ensure the `TaskQueue` is always dropped
154- // on the creator thread.
155- let task_queue = Arc :: downgrade ( & self . task_queue ) ;
153+ let task_queue = self . task_queue . raw_ref ( ) ;
156154
157155 move |runnable| {
158- // The `upgrade()` never fails because all tasks are dropped when the
159- // `Scheduler` is dropped, if a `Waker` is used after that, the
160- // schedule closure will never be called.
161- task_queue. upgrade ( ) . unwrap ( ) . push ( runnable, & notify) ;
156+ // SAFETY:
157+ // `Scheduler` drains and drops all `Runnable`s before it is dropped.
158+ // If this closure is still invoked and can push a `Runnable`, the
159+ // `Scheduler` is necessarily still alive, so the `task_queue` reference
160+ // obtained from `raw_ref()` is valid.
161+ unsafe { task_queue. as_ref ( ) } . push ( runnable, & notify) ;
162162 }
163163 } ;
164164
0 commit comments