1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//! Event Loop Remote
//! Either spawns a new event loop, or re-uses provided one.

use std::{io, thread};
use std::sync::mpsc;
use tokio_core;

use core::futures::{self, Future};

/// Possibly uninitialized event loop remote.
#[derive(Debug)]
pub enum UninitializedRemote {
	/// Shared instance of remote.
	Shared(tokio_core::reactor::Remote),
	/// Event Loop should be spawned by the transport.
	Unspawned,
}

impl UninitializedRemote {
	/// Initializes remote.
	/// In case there is no shared remote, will spawn a new event loop.
	/// Dropping `Remote` closes the loop.
	pub fn initialize(self) -> io::Result<Remote> {
		self.init_with_name("event.loop")
	}

	/// Initializes remote.
	/// In case there is no shared remote, will spawn a new event loop.
	/// Dropping `Remote` closes the loop.
	pub fn init_with_name<T: Into<String>>(self, name: T) -> io::Result<Remote> {
		match self {
			UninitializedRemote::Shared(remote) => Ok(Remote::Shared(remote)),
			UninitializedRemote::Unspawned => RpcEventLoop::with_name(Some(name.into())).map(Remote::Spawned),
		}
	}
}

/// Initialized Remote
#[derive(Debug)]
pub enum Remote {
	/// Shared instance
	Shared(tokio_core::reactor::Remote),
	/// Spawned Event Loop
	Spawned(RpcEventLoop),
}

impl Remote {
	/// Get remote associated with this event loop.
	pub fn remote(&self) -> tokio_core::reactor::Remote {
		match *self {
			Remote::Shared(ref remote) => remote.clone(),
			Remote::Spawned(ref eloop) => eloop.remote(),
		}
	}

	/// Closes underlying event loop (if any!).
	pub fn close(self) {
		if let Remote::Spawned(eloop) = self {
			eloop.close()
		}
	}

	/// Wait for underlying event loop to finish (if any!).
	pub fn wait(self) {
		if let Remote::Spawned(eloop) = self {
			let _ = eloop.wait();
		}
	}
}

/// A handle to running event loop. Dropping the handle will cause event loop to finish.
#[derive(Debug)]
pub struct RpcEventLoop {
	remote: tokio_core::reactor::Remote,
	close: Option<futures::Complete<()>>,
	handle: Option<thread::JoinHandle<()>>,
}

impl Drop for RpcEventLoop {
	fn drop(&mut self) {
		self.close.take().map(|v| v.send(()));
	}
}

impl RpcEventLoop {
	/// Spawns a new thread with the `EventLoop`.
	pub fn spawn() -> io::Result<Self> {
		RpcEventLoop::with_name(None)
	}

	/// Spawns a new named thread with the `EventLoop`.
	pub fn with_name(name: Option<String>) -> io::Result<Self> {
		let (stop, stopped) = futures::oneshot();
		let (tx, rx) = mpsc::channel();
		let mut tb = thread::Builder::new();
		if let Some(name) = name {
			tb = tb.name(name);
		}
		let handle = tb.spawn(move || {
			let el = tokio_core::reactor::Core::new();
			match el {
				Ok(mut el) => {
					tx.send(Ok(el.remote())).expect("Rx is blocking upper thread.");
					let _ = el.run(futures::empty().select(stopped));
				},
				Err(err) => {
					tx.send(Err(err)).expect("Rx is blocking upper thread.");
				}
			}
		}).expect("Couldn't spawn a thread.");
		let remote = rx.recv().expect("tx is transfered to a newly spawned thread.");

		remote.map(|remote| RpcEventLoop {
			remote: remote,
			close: Some(stop),
			handle: Some(handle),
		})
	}

	/// Get remote for this event loop.
	pub fn remote(&self) -> tokio_core::reactor::Remote {
		self.remote.clone()
	}

	/// Blocks current thread and waits until the event loop is finished.
	pub fn wait(mut self) -> thread::Result<()> {
		self.handle.take().expect("Handle is always set before self is consumed.").join()
	}

	/// Finishes this event loop.
	pub fn close(mut self) {
		let _ = self.close.take().expect("Close is always set before self is consumed.").send(()).map_err(|e| {
			warn!("Event Loop is already finished. {:?}", e);
		});
	}
}