11use std:: {
22 any:: Any ,
33 cell:: { Cell , RefCell } ,
4- collections:: { HashSet , VecDeque } ,
4+ collections:: HashSet ,
55 future:: { Future , ready} ,
66 io,
7- marker:: PhantomData ,
87 panic:: AssertUnwindSafe ,
9- rc:: Rc ,
10- sync:: Arc ,
118 task:: { Context , Poll } ,
129 time:: Duration ,
1310} ;
1411
15- use async_task:: { Runnable , Task } ;
12+ use async_task:: Task ;
1613use compio_buf:: IntoInner ;
1714use compio_driver:: {
18- AsRawFd , DriverType , Key , NotifyHandle , OpCode , Proactor , ProactorBuilder , PushEntry , RawFd ,
19- op:: Asyncify ,
15+ AsRawFd , DriverType , Key , OpCode , Proactor , ProactorBuilder , PushEntry , RawFd , op:: Asyncify ,
2016} ;
2117use compio_log:: { debug, instrument} ;
22- use crossbeam_queue:: SegQueue ;
2318use futures_util:: { FutureExt , future:: Either } ;
2419
2520pub ( crate ) mod op;
@@ -29,76 +24,22 @@ pub(crate) mod time;
2924mod buffer_pool;
3025pub use buffer_pool:: * ;
3126
32- mod send_wrapper;
33- use send_wrapper:: SendWrapper ;
27+ mod scheduler;
3428
3529#[ cfg( feature = "time" ) ]
3630use crate :: runtime:: time:: { TimerFuture , TimerKey , TimerRuntime } ;
37- use crate :: { BufResult , affinity:: bind_to_cpu_set, runtime:: op:: OpFuture } ;
31+ use crate :: {
32+ BufResult ,
33+ affinity:: bind_to_cpu_set,
34+ runtime:: { op:: OpFuture , scheduler:: Scheduler } ,
35+ } ;
3836
3937scoped_tls:: scoped_thread_local!( static CURRENT_RUNTIME : Runtime ) ;
4038
4139/// Type alias for `Task<Result<T, Box<dyn Any + Send>>>`, which resolves to an
4240/// `Err` when the spawned future panicked.
4341pub type JoinHandle < T > = Task < Result < T , Box < dyn Any + Send > > > ;
4442
45- struct RunnableQueue {
46- local_runnables : SendWrapper < RefCell < VecDeque < Runnable > > > ,
47- sync_runnables : SegQueue < Runnable > ,
48- }
49-
50- impl RunnableQueue {
51- pub fn new ( ) -> Self {
52- Self {
53- local_runnables : SendWrapper :: new ( RefCell :: new ( VecDeque :: new ( ) ) ) ,
54- sync_runnables : SegQueue :: new ( ) ,
55- }
56- }
57-
58- pub fn schedule ( & self , runnable : Runnable , handle : & NotifyHandle ) {
59- if let Some ( runnables) = self . local_runnables . get ( ) {
60- runnables. borrow_mut ( ) . push_back ( runnable) ;
61- #[ cfg( feature = "notify-always" ) ]
62- handle. notify ( ) . ok ( ) ;
63- } else {
64- self . sync_runnables . push ( runnable) ;
65- handle. notify ( ) . ok ( ) ;
66- }
67- }
68-
69- /// SAFETY: call in the main thread
70- pub unsafe fn run ( & self , event_interval : usize ) -> bool {
71- let local_runnables = self . local_runnables . get_unchecked ( ) ;
72-
73- for _ in 0 ..event_interval {
74- let local_task = local_runnables. borrow_mut ( ) . pop_front ( ) ;
75-
76- // Perform an empty check as a fast path, since `pop()` is more expensive.
77- let sync_task = if self . sync_runnables . is_empty ( ) {
78- None
79- } else {
80- self . sync_runnables . pop ( )
81- } ;
82-
83- match ( local_task, sync_task) {
84- ( Some ( local) , Some ( sync) ) => {
85- local. run ( ) ;
86- sync. run ( ) ;
87- }
88- ( Some ( local) , None ) => {
89- local. run ( ) ;
90- }
91- ( None , Some ( sync) ) => {
92- sync. run ( ) ;
93- }
94- ( None , None ) => break ,
95- }
96- }
97-
98- !( local_runnables. borrow ( ) . is_empty ( ) && self . sync_runnables . is_empty ( ) )
99- }
100- }
101-
10243thread_local ! {
10344 static RUNTIME_ID : Cell <u64 > = const { Cell :: new( 0 ) } ;
10445}
@@ -107,10 +48,9 @@ thread_local! {
10748/// sent to other threads.
10849pub struct Runtime {
10950 driver : RefCell < Proactor > ,
110- runnables : Arc < RunnableQueue > ,
51+ scheduler : Scheduler ,
11152 #[ cfg( feature = "time" ) ]
11253 timer_runtime : RefCell < TimerRuntime > ,
113- event_interval : usize ,
11454 // Runtime id is used to check if the buffer pool is belonged to this runtime or not.
11555 // Without this, if user enable `io-uring-buf-ring` feature then:
11656 // 1. Create a buffer pool at runtime1
@@ -119,9 +59,6 @@ pub struct Runtime {
11959 // - buffer pool will return a wrong buffer which the buffer's data is uninit, that will cause
12060 // UB
12161 id : u64 ,
122- // Other fields don't make it !Send, but actually `local_runnables` implies it should be !Send,
123- // otherwise it won't be valid if the runtime is sent to other threads.
124- _p : PhantomData < Rc < VecDeque < Runnable > > > ,
12562}
12663
12764impl Runtime {
@@ -148,12 +85,10 @@ impl Runtime {
14885 }
14986 Ok ( Self {
15087 driver : RefCell :: new ( proactor_builder. build ( ) ?) ,
151- runnables : Arc :: new ( RunnableQueue :: new ( ) ) ,
88+ scheduler : Scheduler :: new ( * event_interval ) ,
15289 #[ cfg( feature = "time" ) ]
15390 timer_runtime : RefCell :: new ( TimerRuntime :: new ( ) ) ,
154- event_interval : * event_interval,
15591 id,
156- _p : PhantomData ,
15792 } )
15893 }
15994
@@ -202,22 +137,10 @@ impl Runtime {
202137 ///
203138 /// The caller should ensure the captured lifetime long enough.
204139 pub unsafe fn spawn_unchecked < F : Future > ( & self , future : F ) -> Task < F :: Output > {
205- let schedule = {
206- // Use `Weak` to break reference cycle.
207- // `RunnableQueue` -> `Runnable` -> `RunnableQueue`
208- let runnables = Arc :: downgrade ( & self . runnables ) ;
209- let handle = self . driver . borrow ( ) . handle ( ) ;
210-
211- move |runnable| {
212- if let Some ( runnables) = runnables. upgrade ( ) {
213- runnables. schedule ( runnable, & handle) ;
214- }
215- }
216- } ;
140+ let notify = self . driver . borrow ( ) . handle ( ) ;
217141
218- let ( runnable, task) = async_task:: spawn_unchecked ( future, schedule) ;
219- runnable. schedule ( ) ;
220- task
142+ // SAFETY: See the safety comment of this method.
143+ unsafe { self . scheduler . spawn_unchecked ( future, notify) }
221144 }
222145
223146 /// Low level API to control the runtime.
@@ -226,8 +149,7 @@ impl Runtime {
226149 ///
227150 /// The return value indicates whether there are still tasks in the queue.
228151 pub fn run ( & self ) -> bool {
229- // SAFETY: self is !Send + !Sync.
230- unsafe { self . runnables . run ( self . event_interval ) }
152+ self . scheduler . run ( )
231153 }
232154
233155 /// Block on the future till it completes.
0 commit comments