23
23
24
24
#![ allow( unused_variables) ] // because we need them for feature-gated logger
25
25
26
- use std:: collections:: HashMap ;
26
+ use std:: collections:: { HashMap , VecDeque } ;
27
27
use std:: fmt:: { Debug , Display , Formatter } ;
28
28
use std:: os:: unix:: io:: { AsRawFd , RawFd } ;
29
29
use std:: thread:: JoinHandle ;
30
30
use std:: time:: Duration ;
31
31
use std:: { io, thread} ;
32
32
33
33
use crossbeam_channel as chan;
34
+ use crossbeam_channel:: SendError ;
34
35
35
36
use crate :: poller:: { IoType , Poll , Waker , WakerRecv , WakerSend } ;
36
37
use crate :: resource:: WriteError ;
@@ -294,6 +295,7 @@ impl<C, P: Poll> Reactor<C, P> {
294
295
transports : empty ! ( ) ,
295
296
waker : waker_reader,
296
297
timeouts : Timer :: new ( ) ,
298
+ actions : empty ! ( ) ,
297
299
} ;
298
300
299
301
#[ cfg( feature = "log" ) ]
@@ -317,8 +319,9 @@ impl<C, P: Poll> Reactor<C, P> {
317
319
pub fn join ( self ) -> thread:: Result < ( ) > { self . thread . join ( ) }
318
320
}
319
321
320
- enum Ctl < C > {
322
+ pub enum Ctl < C > {
321
323
Cmd ( C ) ,
324
+ Send ( ResourceId , Vec < u8 > ) ,
322
325
Shutdown ,
323
326
}
324
327
@@ -388,6 +391,23 @@ impl<C, W: WakerSend> Controller<C, W> {
388
391
}
389
392
}
390
393
394
+ /// Sender, holding [`Controller`], aware of a specific resource which was the source of the reactor
395
+ /// I/O event.
396
+ pub struct Sender < C , W : WakerSend > {
397
+ controller : Controller < C , W > ,
398
+ resource_id : ResourceId ,
399
+ }
400
+
401
+ impl < C , W : WakerSend > Sender < C , W > {
402
+ /// Sends data to a source of the I/O event, generated inside the reactor and passed to this
403
+ /// [`Sender`] instance.
404
+ pub fn send ( & self , data : impl ToOwned < Owned = Vec < u8 > > ) -> Result < ( ) , SendError < Ctl < C > > >
405
+ where C : ' static {
406
+ self . controller . ctl_send . send ( Ctl :: Send ( self . resource_id , data. to_owned ( ) ) ) ?;
407
+ Ok ( ( ) )
408
+ }
409
+ }
410
+
391
411
/// Internal [`Reactor`] runtime which is run in a dedicated thread.
392
412
///
393
413
/// Use this structure direactly only if you'd like to have the full control over the reactor
@@ -404,6 +424,7 @@ pub struct Runtime<H: Handler, P: Poll> {
404
424
transports : HashMap < ResourceId , H :: Transport > ,
405
425
waker : <P :: Waker as Waker >:: Recv ,
406
426
timeouts : Timer ,
427
+ actions : VecDeque < Action < H :: Listener , H :: Transport > > ,
407
428
}
408
429
409
430
impl < H : Handler , P : Poll > Runtime < H , P > {
@@ -432,11 +453,12 @@ impl<H: Handler, P: Poll> Runtime<H, P> {
432
453
transports : empty ! ( ) ,
433
454
waker : waker_reader,
434
455
timeouts : Timer :: new ( ) ,
456
+ actions : empty ! ( ) ,
435
457
} )
436
458
}
437
459
438
460
/// Provides a copy of a [`Controller`] object which exposes an API to the reactor and a service
439
- /// running inside of its thread.
461
+ /// running inside its thread.
440
462
///
441
463
/// See [`Handler::Command`] for the details.
442
464
pub fn controller ( & self ) -> Controller < H :: Command , <P :: Waker as Waker >:: Send > {
@@ -496,6 +518,9 @@ impl<H: Handler, P: Poll> Runtime<H, P> {
496
518
panic ! ( "control channel is broken" )
497
519
}
498
520
Ok ( Ctl :: Shutdown ) => return self . handle_shutdown ( ) ,
521
+ Ok ( Ctl :: Send ( id, data) ) => {
522
+ self . actions . push_back ( Action :: Send ( id, data) ) ;
523
+ }
499
524
Ok ( Ctl :: Cmd ( cmd) ) => self . service . handle_command ( cmd) ,
500
525
}
501
526
}
@@ -580,7 +605,7 @@ impl<H: Handler, P: Poll> Runtime<H, P> {
580
605
}
581
606
582
607
fn handle_actions ( & mut self , time : Timestamp ) {
583
- while let Some ( action) = self . service . next ( ) {
608
+ while let Some ( action) = self . actions . pop_front ( ) . or_else ( || self . service . next ( ) ) {
584
609
#[ cfg( feature = "log" ) ]
585
610
log:: trace!( target: "reactor" , "Handling action {action} from the service" ) ;
586
611
0 commit comments