use std::sync::*; use std::mem; use std::thread::{JoinHandle, self}; use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; use crossbeam::sync::chase_lev; use io::service::{HandlerId, IoChannel, IoContext}; use io::{IoHandler}; pub enum WorkType { Readable, Writable, Hup, Timeout, Message(Message) } pub struct Work { pub work_type: WorkType, pub token: usize, pub handler_id: HandlerId, pub handler: Arc>, } /// An IO worker thread /// Sorts them ready for blockchain insertion. pub struct Worker { thread: Option>, wait: Arc, deleting: Arc, } impl Worker { /// Creates a new worker instance. pub fn new(index: usize, stealer: chase_lev::Stealer>, channel: IoChannel, wait: Arc, wait_mutex: Arc>) -> Worker where Message: Send + Sync + Clone + 'static { let deleting = Arc::new(AtomicBool::new(false)); let mut worker = Worker { thread: None, wait: wait.clone(), deleting: deleting.clone(), }; worker.thread = Some(thread::Builder::new().name(format!("IO Worker #{}", index)).spawn( move || Worker::work_loop(stealer, channel.clone(), wait, wait_mutex.clone(), deleting)) .expect("Error creating worker thread")); worker } fn work_loop(stealer: chase_lev::Stealer>, channel: IoChannel, wait: Arc, wait_mutex: Arc>, deleting: Arc) where Message: Send + Sync + Clone + 'static { while !deleting.load(AtomicOrdering::Relaxed) { { let lock = wait_mutex.lock().unwrap(); let _ = wait.wait(lock).unwrap(); if deleting.load(AtomicOrdering::Relaxed) { return; } } loop { match stealer.steal() { chase_lev::Steal::Data(work) => { Worker::do_work(work, channel.clone()); } _ => break } } } } fn do_work(work: Work, channel: IoChannel) where Message: Send + Sync + Clone + 'static { match work.work_type { WorkType::Readable => { work.handler.stream_readable(&mut IoContext::new(channel, work.handler_id), work.token); }, WorkType::Writable => { work.handler.stream_writable(&mut IoContext::new(channel, work.handler_id), work.token); } WorkType::Hup => { work.handler.stream_hup(&mut IoContext::new(channel, work.handler_id), work.token); } WorkType::Timeout => { work.handler.timeout(&mut IoContext::new(channel, work.handler_id), work.token); } WorkType::Message(message) => { work.handler.message(&mut IoContext::new(channel, work.handler_id), &message); } } } } impl Drop for Worker { fn drop(&mut self) { self.deleting.store(true, AtomicOrdering::Relaxed); self.wait.notify_all(); let thread = mem::replace(&mut self.thread, None).unwrap(); thread.join().unwrap(); } }