@@ -2,6 +2,10 @@ use std::cell::RefCell;
22use std:: collections:: HashMap ;
33use std:: future:: Future ;
44use std:: pin:: Pin ;
5+ use std:: sync:: {
6+ atomic:: { AtomicBool , Ordering } ,
7+ Arc ,
8+ } ;
59use std:: task:: { Context , Poll } ;
610
711use crate :: {
@@ -10,15 +14,15 @@ use crate::{
1014 logging:: { error, info} ,
1115 set_state, timer, Address , BuildError , LazyLoadBlob , Message , Request , SendError ,
1216} ;
13- use futures_util:: task:: noop_waker_ref;
17+ use futures_util:: task:: { waker_ref, ArcWake } ;
18+ use futures_channel:: { mpsc, oneshot} ;
1419use serde:: { Deserialize , Serialize } ;
1520use thiserror:: Error ;
1621use uuid:: Uuid ;
1722
1823thread_local ! {
1924 static SPAWN_QUEUE : RefCell <Vec <Pin <Box <dyn Future <Output = ( ) >>>>> = RefCell :: new( Vec :: new( ) ) ;
2025
21-
2226 pub static APP_CONTEXT : RefCell <AppContext > = RefCell :: new( AppContext {
2327 hidden_state: None ,
2428 executor: Executor :: new( ) ,
@@ -146,10 +150,53 @@ pub struct Executor {
146150 tasks : Vec < Pin < Box < dyn Future < Output = ( ) > > > > ,
147151}
148152
149- pub fn spawn ( fut : impl Future < Output = ( ) > + ' static ) {
153+ struct ExecutorWakeFlag {
154+ triggered : AtomicBool ,
155+ }
156+
157+ impl ExecutorWakeFlag {
158+ fn new ( ) -> Self {
159+ Self {
160+ triggered : AtomicBool :: new ( false ) ,
161+ }
162+ }
163+
164+ fn take ( & self ) -> bool {
165+ self . triggered . swap ( false , Ordering :: SeqCst )
166+ }
167+ }
168+
169+ impl ArcWake for ExecutorWakeFlag {
170+ fn wake_by_ref ( arc_self : & Arc < Self > ) {
171+ arc_self. triggered . store ( true , Ordering :: SeqCst ) ;
172+ }
173+ }
174+
175+ pub struct JoinHandle < T > {
176+ receiver : oneshot:: Receiver < T > ,
177+ }
178+
179+ impl < T > Future for JoinHandle < T > {
180+ type Output = Result < T , oneshot:: Canceled > ;
181+
182+ fn poll ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
183+ let receiver = & mut self . get_mut ( ) . receiver ;
184+ Pin :: new ( receiver) . poll ( cx)
185+ }
186+ }
187+
188+ pub fn spawn < T > ( fut : impl Future < Output = T > + ' static ) -> JoinHandle < T >
189+ where
190+ T : ' static ,
191+ {
192+ let ( sender, receiver) = oneshot:: channel ( ) ;
150193 SPAWN_QUEUE . with ( |queue| {
151- queue. borrow_mut ( ) . push ( Box :: pin ( fut) ) ;
152- } )
194+ queue. borrow_mut ( ) . push ( Box :: pin ( async move {
195+ let result = fut. await ;
196+ let _ = sender. send ( result) ;
197+ } ) ) ;
198+ } ) ;
199+ JoinHandle { receiver }
153200}
154201
155202impl Executor {
@@ -158,19 +205,24 @@ impl Executor {
158205 }
159206
160207 pub fn poll_all_tasks ( & mut self ) {
208+ let wake_flag = Arc :: new ( ExecutorWakeFlag :: new ( ) ) ;
161209 loop {
162210 // Drain any newly spawned tasks into our task list
163211 SPAWN_QUEUE . with ( |queue| {
164212 self . tasks . append ( & mut queue. borrow_mut ( ) ) ;
165213 } ) ;
166214
167- // Poll all tasks, collecting completed ones
215+ // Poll all tasks, collecting completed ones.
216+ // Put waker into context so tasks can wake the executor if needed.
168217 let mut completed = Vec :: new ( ) ;
169- let mut ctx = Context :: from_waker ( noop_waker_ref ( ) ) ;
218+ {
219+ let waker = waker_ref ( & wake_flag) ;
220+ let mut ctx = Context :: from_waker ( & waker) ;
170221
171- for i in 0 ..self . tasks . len ( ) {
172- if let Poll :: Ready ( ( ) ) = self . tasks [ i] . as_mut ( ) . poll ( & mut ctx) {
173- completed. push ( i) ;
222+ for i in 0 ..self . tasks . len ( ) {
223+ if let Poll :: Ready ( ( ) ) = self . tasks [ i] . as_mut ( ) . poll ( & mut ctx) {
224+ completed. push ( i) ;
225+ }
174226 }
175227 }
176228
@@ -181,9 +233,10 @@ impl Executor {
181233
182234 // Check if there are new tasks spawned during polling
183235 let has_new_tasks = SPAWN_QUEUE . with ( |queue| !queue. borrow ( ) . is_empty ( ) ) ;
236+ // Check if any task woke the executor that needs to be re-polled
237+ let was_woken = wake_flag. take ( ) ;
184238
185- // Continue if new tasks were spawned, otherwise we're done
186- if !has_new_tasks {
239+ if !has_new_tasks && !was_woken {
187240 break ;
188241 }
189242 }
0 commit comments