From 164193fe823c92346261918261a46f3528415fb7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 5 Aug 2016 15:58:14 -0700 Subject: [PATCH] Add a method to add data to an event loop directly Avoids Send entirely --- src/event_loop.rs | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/event_loop.rs b/src/event_loop.rs index 68bc18c35..fb145e9c3 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -3,6 +3,7 @@ use std::cell::{Cell, RefCell}; use std::io::{self, ErrorKind}; use std::marker; use std::mem; +use std::rc::Rc; use std::sync::Arc; use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; use std::sync::mpsc; @@ -47,6 +48,12 @@ pub struct Loop { // `timeouts` slab. timer_wheel: RefCell>, timeouts: RefCell>, + + // A `Loop` cannot be sent to other threads as it's used as a proxy for data + // that belongs to the thread the loop was running on at some point. In + // other words, the safety of `DropBox` below relies on loops not crossing + // threads. + _marker: marker::PhantomData>, } struct MioSender { @@ -128,6 +135,7 @@ impl Loop { dispatch: RefCell::new(Slab::new_starting_at(1, SLAB_CAPACITY)), timeouts: RefCell::new(Slab::new_starting_at(0, SLAB_CAPACITY)), timer_wheel: RefCell::new(TimerWheel::new()), + _marker: marker::PhantomData, }) } @@ -143,6 +151,22 @@ impl Loop { } } + /// Creates a new `LoopData` handle by associating data to be directly + /// stored by this event loop. + /// + /// This function is useful for when storing non-`Send` data inside of a + /// future. The `LoopData` handle is itself `Send + 'static` regardless + /// of the underlying `A`. That is, for example, you can create a handle to + /// some data that contains an `Rc`, for example. + pub fn add_loop_data(&self, a: A) -> LoopData + where A: Any, + { + LoopData { + data: DropBox::new_on(a, self), + handle: self.handle(), + } + } + /// Runs a future until completion, driving the event loop while we're /// otherwise waiting for the future to complete. /// @@ -776,7 +800,7 @@ impl Drop for LoopData { mod dropbox { use std::any::Any; use std::mem; - use super::CURRENT_LOOP; + use super::{CURRENT_LOOP, Loop}; pub struct DropBox { id: usize, @@ -801,6 +825,16 @@ mod dropbox { } } + /// Creates a new `DropBox` pinned to the thread of `Loop`. + /// + /// Will panic if `CURRENT_LOOP` isn't set. + pub fn new_on(a: A, lp: &Loop) -> DropBox { + DropBox { + id: lp.id, + inner: Some(Box::new(a)), + } + } + /// Downcasts this `DropBox` to the type specified. /// /// Normally this always succeeds as it's a static assertion that we