Make mio optional in ethcore-io (#8537)
* Make mio optional in ethcore-io * Add some annotations, plus a check for features * Increase timer for test
This commit is contained in:
committed by
Afri Schoedon
parent
6e2e08628a
commit
1b8f299df2
@@ -54,30 +54,59 @@
|
||||
//! // Drop the service
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! # Mio vs non-mio
|
||||
//!
|
||||
//! This library has two modes: mio and not mio. The `mio` feature can be activated or deactivated
|
||||
//! when compiling or depending on the library.
|
||||
//!
|
||||
//! Without mio, only timers and message-passing are available. With mio, you can also use
|
||||
//! low-level sockets provided by mio.
|
||||
//!
|
||||
//! The non-mio mode exists because the `mio` library doesn't compile on platforms such as
|
||||
//! emscripten.
|
||||
|
||||
//TODO: use Poll from mio
|
||||
#![allow(deprecated)]
|
||||
|
||||
#[cfg(feature = "mio")]
|
||||
extern crate mio;
|
||||
#[macro_use]
|
||||
extern crate log as rlog;
|
||||
extern crate slab;
|
||||
extern crate crossbeam;
|
||||
extern crate parking_lot;
|
||||
extern crate num_cpus;
|
||||
extern crate timer;
|
||||
extern crate fnv;
|
||||
extern crate time;
|
||||
|
||||
mod service;
|
||||
#[cfg(feature = "mio")]
|
||||
mod service_mio;
|
||||
#[cfg(not(feature = "mio"))]
|
||||
mod service_non_mio;
|
||||
#[cfg(feature = "mio")]
|
||||
mod worker;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::{fmt, error};
|
||||
#[cfg(feature = "mio")]
|
||||
use mio::deprecated::{EventLoop, NotifyError};
|
||||
#[cfg(feature = "mio")]
|
||||
use mio::Token;
|
||||
|
||||
pub use worker::LOCAL_STACK_SIZE;
|
||||
thread_local! {
|
||||
/// Stack size
|
||||
/// Should be modified if it is changed in Rust since it is no way
|
||||
/// to know or get it
|
||||
pub static LOCAL_STACK_SIZE: Cell<usize> = Cell::new(::std::env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok()).unwrap_or(2 * 1024 * 1024));
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// IO Error
|
||||
pub enum IoError {
|
||||
/// Low level error from mio crate
|
||||
#[cfg(feature = "mio")]
|
||||
Mio(::std::io::Error),
|
||||
/// Error concerning the Rust standard library's IO subsystem.
|
||||
StdIo(::std::io::Error),
|
||||
@@ -88,6 +117,7 @@ impl fmt::Display for IoError {
|
||||
// just defer to the std implementation for now.
|
||||
// we can refine the formatting when more variants are added.
|
||||
match *self {
|
||||
#[cfg(feature = "mio")]
|
||||
IoError::Mio(ref std_err) => std_err.fmt(f),
|
||||
IoError::StdIo(ref std_err) => std_err.fmt(f),
|
||||
}
|
||||
@@ -106,8 +136,9 @@ impl From<::std::io::Error> for IoError {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Message> From<NotifyError<service::IoMessage<Message>>> for IoError where Message: Send {
|
||||
fn from(_err: NotifyError<service::IoMessage<Message>>) -> IoError {
|
||||
#[cfg(feature = "mio")]
|
||||
impl<Message> From<NotifyError<service_mio::IoMessage<Message>>> for IoError where Message: Send {
|
||||
fn from(_err: NotifyError<service_mio::IoMessage<Message>>) -> IoError {
|
||||
IoError::Mio(::std::io::Error::new(::std::io::ErrorKind::ConnectionAborted, "Network IO notification error"))
|
||||
}
|
||||
}
|
||||
@@ -123,58 +154,120 @@ pub trait IoHandler<Message>: Send + Sync where Message: Send + Sync + 'static {
|
||||
/// Called when a broadcasted message is received. The message can only be sent from a different IO handler.
|
||||
fn message(&self, _io: &IoContext<Message>, _message: &Message) {}
|
||||
/// Called when an IO stream gets closed
|
||||
#[cfg(feature = "mio")]
|
||||
fn stream_hup(&self, _io: &IoContext<Message>, _stream: StreamToken) {}
|
||||
/// Called when an IO stream can be read from
|
||||
#[cfg(feature = "mio")]
|
||||
fn stream_readable(&self, _io: &IoContext<Message>, _stream: StreamToken) {}
|
||||
/// Called when an IO stream can be written to
|
||||
#[cfg(feature = "mio")]
|
||||
fn stream_writable(&self, _io: &IoContext<Message>, _stream: StreamToken) {}
|
||||
/// Register a new stream with the event loop
|
||||
#[cfg(feature = "mio")]
|
||||
fn register_stream(&self, _stream: StreamToken, _reg: Token, _event_loop: &mut EventLoop<IoManager<Message>>) {}
|
||||
/// Re-register a stream with the event loop
|
||||
#[cfg(feature = "mio")]
|
||||
fn update_stream(&self, _stream: StreamToken, _reg: Token, _event_loop: &mut EventLoop<IoManager<Message>>) {}
|
||||
/// Deregister a stream. Called whenstream is removed from event loop
|
||||
#[cfg(feature = "mio")]
|
||||
fn deregister_stream(&self, _stream: StreamToken, _event_loop: &mut EventLoop<IoManager<Message>>) {}
|
||||
}
|
||||
|
||||
pub use service::TimerToken;
|
||||
pub use service::StreamToken;
|
||||
pub use service::IoContext;
|
||||
pub use service::IoService;
|
||||
pub use service::IoChannel;
|
||||
pub use service::IoManager;
|
||||
pub use service::TOKENS_PER_HANDLER;
|
||||
#[cfg(feature = "mio")]
|
||||
pub use service_mio::{TimerToken, StreamToken, IoContext, IoService, IoChannel, IoManager, TOKENS_PER_HANDLER};
|
||||
#[cfg(not(feature = "mio"))]
|
||||
pub use service_non_mio::{TimerToken, IoContext, IoService, IoChannel, TOKENS_PER_HANDLER};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use super::*;
|
||||
|
||||
struct MyHandler;
|
||||
#[test]
|
||||
fn send_message_to_handler() {
|
||||
struct MyHandler(atomic::AtomicBool);
|
||||
|
||||
#[derive(Clone)]
|
||||
struct MyMessage {
|
||||
data: u32
|
||||
}
|
||||
|
||||
impl IoHandler<MyMessage> for MyHandler {
|
||||
fn initialize(&self, io: &IoContext<MyMessage>) {
|
||||
io.register_timer(0, Duration::from_secs(1)).unwrap();
|
||||
#[derive(Clone)]
|
||||
struct MyMessage {
|
||||
data: u32
|
||||
}
|
||||
|
||||
fn timeout(&self, _io: &IoContext<MyMessage>, timer: TimerToken) {
|
||||
println!("Timeout {}", timer);
|
||||
impl IoHandler<MyMessage> for MyHandler {
|
||||
fn message(&self, _io: &IoContext<MyMessage>, message: &MyMessage) {
|
||||
assert_eq!(message.data, 5);
|
||||
self.0.store(true, atomic::Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
fn message(&self, _io: &IoContext<MyMessage>, message: &MyMessage) {
|
||||
println!("Message {}", message.data);
|
||||
}
|
||||
let handler = Arc::new(MyHandler(atomic::AtomicBool::new(false)));
|
||||
|
||||
let service = IoService::<MyMessage>::start().expect("Error creating network service");
|
||||
service.register_handler(handler.clone()).unwrap();
|
||||
|
||||
service.send_message(MyMessage { data: 5 }).unwrap();
|
||||
|
||||
thread::sleep(Duration::from_secs(5));
|
||||
assert!(handler.0.load(atomic::Ordering::SeqCst));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_service_register_handler () {
|
||||
fn timeout_working() {
|
||||
struct MyHandler(atomic::AtomicBool);
|
||||
|
||||
#[derive(Clone)]
|
||||
struct MyMessage {
|
||||
data: u32
|
||||
}
|
||||
|
||||
impl IoHandler<MyMessage> for MyHandler {
|
||||
fn initialize(&self, io: &IoContext<MyMessage>) {
|
||||
io.register_timer_once(1234, Duration::from_millis(500)).unwrap();
|
||||
}
|
||||
|
||||
fn timeout(&self, _io: &IoContext<MyMessage>, timer: TimerToken) {
|
||||
assert_eq!(timer, 1234);
|
||||
assert!(!self.0.swap(true, atomic::Ordering::SeqCst));
|
||||
}
|
||||
}
|
||||
|
||||
let handler = Arc::new(MyHandler(atomic::AtomicBool::new(false)));
|
||||
|
||||
let service = IoService::<MyMessage>::start().expect("Error creating network service");
|
||||
service.register_handler(Arc::new(MyHandler)).unwrap();
|
||||
service.register_handler(handler.clone()).unwrap();
|
||||
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
assert!(handler.0.load(atomic::Ordering::SeqCst));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_timeout_working() {
|
||||
struct MyHandler(atomic::AtomicUsize);
|
||||
|
||||
#[derive(Clone)]
|
||||
struct MyMessage {
|
||||
data: u32
|
||||
}
|
||||
|
||||
impl IoHandler<MyMessage> for MyHandler {
|
||||
fn initialize(&self, io: &IoContext<MyMessage>) {
|
||||
io.register_timer(1234, Duration::from_millis(500)).unwrap();
|
||||
}
|
||||
|
||||
fn timeout(&self, _io: &IoContext<MyMessage>, timer: TimerToken) {
|
||||
assert_eq!(timer, 1234);
|
||||
self.0.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
let handler = Arc::new(MyHandler(atomic::AtomicUsize::new(0)));
|
||||
|
||||
let service = IoService::<MyMessage>::start().expect("Error creating network service");
|
||||
service.register_handler(handler.clone()).unwrap();
|
||||
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
assert!(handler.0.load(atomic::Ordering::SeqCst) >= 2);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user