1
- use std:: {
2
- future:: Future ,
3
- sync:: {
4
- atomic:: { AtomicUsize , Ordering } ,
5
- mpsc, Arc ,
6
- } ,
7
- } ;
8
-
9
- use crate :: { DroppableFuture , TaskIdentifier , TickedTimer } ;
10
-
11
- #[ derive( Debug ) ]
12
- pub enum TaskState {
13
- Spawn ( TaskIdentifier ) ,
14
- Wake ( TaskIdentifier ) ,
15
- Tick ( TaskIdentifier , f64 ) ,
16
- Drop ( TaskIdentifier ) ,
17
- }
1
+ use std:: future:: Future ;
18
2
19
- pub type Task < T > = async_task:: Task < T > ;
20
- type Payload = ( TaskIdentifier , async_task:: Runnable ) ;
3
+ use crate :: {
4
+ new_split_ticked_async_executor, Task , TaskIdentifier , TaskState , TickedAsyncExecutorSpawner ,
5
+ TickedAsyncExecutorTicker , TickedTimer ,
6
+ } ;
21
7
22
8
pub struct TickedAsyncExecutor < O > {
23
- channel : ( mpsc:: Sender < Payload > , mpsc:: Receiver < Payload > ) ,
24
- num_woken_tasks : Arc < AtomicUsize > ,
25
-
26
- num_spawned_tasks : Arc < AtomicUsize > ,
27
-
28
- // TODO, Or we need a Single Producer - Multi Consumer channel i.e Broadcast channel
29
- // Broadcast recv channel should be notified when there are new messages in the queue
30
- // Broadcast channel must also be able to remove older/stale messages (like a RingBuffer)
31
- observer : O ,
32
-
33
- tick_event : tokio:: sync:: watch:: Sender < f64 > ,
9
+ spawner : TickedAsyncExecutorSpawner < O > ,
10
+ ticker : TickedAsyncExecutorTicker < O > ,
34
11
}
35
12
36
13
impl Default for TickedAsyncExecutor < fn ( TaskState ) > {
44
21
O : Fn ( TaskState ) + Clone + Send + Sync + ' static ,
45
22
{
46
23
pub fn new ( observer : O ) -> Self {
47
- Self {
48
- channel : mpsc:: channel ( ) ,
49
- num_woken_tasks : Arc :: new ( AtomicUsize :: new ( 0 ) ) ,
50
- num_spawned_tasks : Arc :: new ( AtomicUsize :: new ( 0 ) ) ,
51
- observer,
52
- tick_event : tokio:: sync:: watch:: channel ( 1.0 ) . 0 ,
53
- }
24
+ let ( spawner, ticker) = new_split_ticked_async_executor ( observer) ;
25
+ Self { spawner, ticker }
54
26
}
55
27
56
28
pub fn spawn_local < T > (
@@ -61,16 +33,11 @@ where
61
33
where
62
34
T : ' static ,
63
35
{
64
- let identifier = identifier. into ( ) ;
65
- let future = self . droppable_future ( identifier. clone ( ) , future) ;
66
- let schedule = self . runnable_schedule_cb ( identifier) ;
67
- let ( runnable, task) = async_task:: spawn_local ( future, schedule) ;
68
- runnable. schedule ( ) ;
69
- task
36
+ self . spawner . spawn_local ( identifier, future)
70
37
}
71
38
72
39
pub fn num_tasks ( & self ) -> usize {
73
- self . num_spawned_tasks . load ( Ordering :: Relaxed )
40
+ self . spawner . num_tasks ( )
74
41
}
75
42
76
43
/// Run the woken tasks once
@@ -81,72 +48,25 @@ where
81
48
/// `limit` is used to limit the number of woken tasks run per tick
82
49
/// - None would imply that there is no limit (all woken tasks would run)
83
50
/// - Some(limit) would imply that [0..limit] woken tasks would run,
84
- /// even if more tasks are woken.
51
+ /// even if more tasks are woken.
85
52
///
86
53
/// Tick is !Sync i.e cannot be invoked from multiple threads
87
54
///
88
55
/// NOTE: Will not run tasks that are woken/scheduled immediately after `Runnable::run`
89
56
pub fn tick ( & self , delta : f64 , limit : Option < usize > ) {
90
- let _r = self . tick_event . send ( delta) ;
91
-
92
- let mut num_woken_tasks = self . num_woken_tasks . load ( Ordering :: Relaxed ) ;
93
- if let Some ( limit) = limit {
94
- // Woken tasks should not exceed the allowed limit
95
- num_woken_tasks = num_woken_tasks. min ( limit) ;
96
- }
97
-
98
- self . channel
99
- . 1
100
- . try_iter ( )
101
- . take ( num_woken_tasks)
102
- . for_each ( |( identifier, runnable) | {
103
- ( self . observer ) ( TaskState :: Tick ( identifier, delta) ) ;
104
- runnable. run ( ) ;
105
- } ) ;
106
- self . num_woken_tasks
107
- . fetch_sub ( num_woken_tasks, Ordering :: Relaxed ) ;
57
+ self . ticker . tick ( delta, limit) ;
108
58
}
109
59
110
60
pub fn create_timer ( & self ) -> TickedTimer {
111
- let tick_recv = self . tick_event . subscribe ( ) ;
112
- TickedTimer { tick_recv }
61
+ self . spawner . create_timer ( )
113
62
}
114
63
115
64
pub fn tick_channel ( & self ) -> tokio:: sync:: watch:: Receiver < f64 > {
116
- self . tick_event . subscribe ( )
117
- }
118
-
119
- fn droppable_future < F > (
120
- & self ,
121
- identifier : TaskIdentifier ,
122
- future : F ,
123
- ) -> DroppableFuture < F , impl Fn ( ) >
124
- where
125
- F : Future ,
126
- {
127
- let observer = self . observer . clone ( ) ;
128
-
129
- // Spawn Task
130
- self . num_spawned_tasks . fetch_add ( 1 , Ordering :: Relaxed ) ;
131
- observer ( TaskState :: Spawn ( identifier. clone ( ) ) ) ;
132
-
133
- // Droppable Future registering on_drop callback
134
- let num_spawned_tasks = self . num_spawned_tasks . clone ( ) ;
135
- DroppableFuture :: new ( future, move || {
136
- num_spawned_tasks. fetch_sub ( 1 , Ordering :: Relaxed ) ;
137
- observer ( TaskState :: Drop ( identifier. clone ( ) ) ) ;
138
- } )
65
+ self . spawner . tick_channel ( )
139
66
}
140
67
141
- fn runnable_schedule_cb ( & self , identifier : TaskIdentifier ) -> impl Fn ( async_task:: Runnable ) {
142
- let sender = self . channel . 0 . clone ( ) ;
143
- let num_woken_tasks = self . num_woken_tasks . clone ( ) ;
144
- let observer = self . observer . clone ( ) ;
145
- move |runnable| {
146
- sender. send ( ( identifier. clone ( ) , runnable) ) . unwrap_or ( ( ) ) ;
147
- num_woken_tasks. fetch_add ( 1 , Ordering :: Relaxed ) ;
148
- observer ( TaskState :: Wake ( identifier. clone ( ) ) ) ;
149
- }
68
+ pub fn wait_till_completed ( & self , delta : f64 ) {
69
+ self . ticker . wait_till_completed ( delta) ;
150
70
}
151
71
}
152
72
@@ -220,9 +140,7 @@ mod tests {
220
140
assert_eq ! ( executor. num_tasks( ) , 3 ) ;
221
141
222
142
// Since we have cancelled the tasks above, the loops should eventually end
223
- while executor. num_tasks ( ) != 0 {
224
- executor. tick ( DELTA , None ) ;
225
- }
143
+ executor. wait_till_completed ( DELTA ) ;
226
144
}
227
145
228
146
#[ test]
@@ -311,8 +229,8 @@ mod tests {
311
229
}
312
230
313
231
for i in 0 ..10 {
314
- let woken_tasks = executor. num_woken_tasks . load ( Ordering :: Relaxed ) ;
315
- assert_eq ! ( woken_tasks , 10 - i) ;
232
+ let num_tasks = executor. num_tasks ( ) ;
233
+ assert_eq ! ( num_tasks , 10 - i) ;
316
234
executor. tick ( 0.1 , Some ( 1 ) ) ;
317
235
}
318
236
0 commit comments