Skip to content

Commit d89c3f9

Browse files
committed
Sender type able to send data directly to the source of an I/O event
1 parent 773fff9 commit d89c3f9

File tree

2 files changed

+30
-5
lines changed

2 files changed

+30
-5
lines changed

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,4 @@ pub use resource::{
8181
};
8282
pub use timeouts::{Timer, Timestamp};
8383

84-
pub use self::reactor::{Action, Controller, Error, Handler, Reactor, Runtime};
84+
pub use self::reactor::{Action, Controller, Error, Handler, Reactor, Runtime, Sender};

src/reactor.rs

+29-4
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,15 @@
2323

2424
#![allow(unused_variables)] // because we need them for feature-gated logger
2525

26-
use std::collections::HashMap;
26+
use std::collections::{HashMap, VecDeque};
2727
use std::fmt::{Debug, Display, Formatter};
2828
use std::os::unix::io::{AsRawFd, RawFd};
2929
use std::thread::JoinHandle;
3030
use std::time::Duration;
3131
use std::{io, thread};
3232

3333
use crossbeam_channel as chan;
34+
use crossbeam_channel::SendError;
3435

3536
use crate::poller::{IoType, Poll, Waker, WakerRecv, WakerSend};
3637
use crate::resource::WriteError;
@@ -294,6 +295,7 @@ impl<C, P: Poll> Reactor<C, P> {
294295
transports: empty!(),
295296
waker: waker_reader,
296297
timeouts: Timer::new(),
298+
actions: empty!(),
297299
};
298300

299301
#[cfg(feature = "log")]
@@ -317,8 +319,9 @@ impl<C, P: Poll> Reactor<C, P> {
317319
pub fn join(self) -> thread::Result<()> { self.thread.join() }
318320
}
319321

320-
enum Ctl<C> {
322+
pub enum Ctl<C> {
321323
Cmd(C),
324+
Send(ResourceId, Vec<u8>),
322325
Shutdown,
323326
}
324327

@@ -388,6 +391,23 @@ impl<C, W: WakerSend> Controller<C, W> {
388391
}
389392
}
390393

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+
391411
/// Internal [`Reactor`] runtime which is run in a dedicated thread.
392412
///
393413
/// 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> {
404424
transports: HashMap<ResourceId, H::Transport>,
405425
waker: <P::Waker as Waker>::Recv,
406426
timeouts: Timer,
427+
actions: VecDeque<Action<H::Listener, H::Transport>>,
407428
}
408429

409430
impl<H: Handler, P: Poll> Runtime<H, P> {
@@ -432,11 +453,12 @@ impl<H: Handler, P: Poll> Runtime<H, P> {
432453
transports: empty!(),
433454
waker: waker_reader,
434455
timeouts: Timer::new(),
456+
actions: empty!(),
435457
})
436458
}
437459

438460
/// 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.
440462
///
441463
/// See [`Handler::Command`] for the details.
442464
pub fn controller(&self) -> Controller<H::Command, <P::Waker as Waker>::Send> {
@@ -496,6 +518,9 @@ impl<H: Handler, P: Poll> Runtime<H, P> {
496518
panic!("control channel is broken")
497519
}
498520
Ok(Ctl::Shutdown) => return self.handle_shutdown(),
521+
Ok(Ctl::Send(id, data)) => {
522+
self.actions.push_back(Action::Send(id, data));
523+
}
499524
Ok(Ctl::Cmd(cmd)) => self.service.handle_command(cmd),
500525
}
501526
}
@@ -580,7 +605,7 @@ impl<H: Handler, P: Poll> Runtime<H, P> {
580605
}
581606

582607
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()) {
584609
#[cfg(feature = "log")]
585610
log::trace!(target: "reactor", "Handling action {action} from the service");
586611

0 commit comments

Comments
 (0)