2020-01-17 14:27:28 +01:00
|
|
|
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
|
2019-01-07 11:33:07 +01:00
|
|
|
// This file is part of Parity Ethereum.
|
2016-02-05 13:40:41 +01:00
|
|
|
|
2019-01-07 11:33:07 +01:00
|
|
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
2016-02-05 13:40:41 +01:00
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
2019-01-07 11:33:07 +01:00
|
|
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
2016-02-05 13:40:41 +01:00
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
2019-01-07 11:33:07 +01:00
|
|
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
2016-02-05 13:40:41 +01:00
|
|
|
|
2019-08-08 09:41:22 +02:00
|
|
|
use std::{
|
|
|
|
sync::{Arc, atomic::{AtomicBool, Ordering as AtomicOrdering}},
|
|
|
|
thread::{self, JoinHandle},
|
|
|
|
};
|
2016-07-13 19:59:59 +02:00
|
|
|
|
2019-08-08 09:41:22 +02:00
|
|
|
use crossbeam_deque as deque;
|
|
|
|
use futures::future::{self, Loop};
|
|
|
|
use log::{trace, error};
|
2018-08-22 16:01:07 +02:00
|
|
|
use parking_lot::{Condvar, Mutex};
|
2019-08-08 09:41:22 +02:00
|
|
|
use tokio;
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
IoHandler,
|
|
|
|
LOCAL_STACK_SIZE,
|
|
|
|
service_mio::{HandlerId, IoChannel, IoContext},
|
|
|
|
};
|
2016-01-21 17:21:51 +01:00
|
|
|
|
2016-10-06 18:42:54 +02:00
|
|
|
const STACK_SIZE: usize = 16*1024*1024;
|
|
|
|
|
2016-01-21 17:21:51 +01:00
|
|
|
pub enum WorkType<Message> {
|
|
|
|
Readable,
|
|
|
|
Writable,
|
|
|
|
Hup,
|
|
|
|
Timeout,
|
2018-05-09 08:49:34 +02:00
|
|
|
Message(Arc<Message>)
|
2016-01-21 17:21:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Work<Message> {
|
|
|
|
pub work_type: WorkType<Message>,
|
|
|
|
pub token: usize,
|
|
|
|
pub handler_id: HandlerId,
|
2019-08-08 09:41:22 +02:00
|
|
|
pub handler: Arc<dyn IoHandler<Message>>,
|
2016-01-21 17:21:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// An IO worker thread
|
|
|
|
/// Sorts them ready for blockchain insertion.
|
|
|
|
pub struct Worker {
|
|
|
|
thread: Option<JoinHandle<()>>,
|
2018-08-22 16:01:07 +02:00
|
|
|
wait: Arc<Condvar>,
|
2016-01-21 17:21:51 +01:00
|
|
|
deleting: Arc<AtomicBool>,
|
2018-08-22 16:01:07 +02:00
|
|
|
wait_mutex: Arc<Mutex<()>>,
|
2016-01-21 17:21:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Worker {
|
|
|
|
/// Creates a new worker instance.
|
2019-08-08 09:41:22 +02:00
|
|
|
pub fn new<Message>(
|
|
|
|
index: usize,
|
|
|
|
stealer: deque::Stealer<Work<Message>>,
|
|
|
|
channel: IoChannel<Message>,
|
|
|
|
wait: Arc<Condvar>,
|
|
|
|
wait_mutex: Arc<Mutex<()>>,
|
|
|
|
) -> Worker
|
|
|
|
where Message: Send + Sync + 'static
|
|
|
|
{
|
2016-01-21 17:21:51 +01:00
|
|
|
let deleting = Arc::new(AtomicBool::new(false));
|
|
|
|
let mut worker = Worker {
|
|
|
|
thread: None,
|
|
|
|
wait: wait.clone(),
|
|
|
|
deleting: deleting.clone(),
|
2016-02-16 17:53:31 +01:00
|
|
|
wait_mutex: wait_mutex.clone(),
|
2016-01-21 17:21:51 +01:00
|
|
|
};
|
2016-10-06 18:42:54 +02:00
|
|
|
worker.thread = Some(thread::Builder::new().stack_size(STACK_SIZE).name(format!("IO Worker #{}", index)).spawn(
|
2016-02-10 12:50:27 +01:00
|
|
|
move || {
|
2016-10-06 18:42:54 +02:00
|
|
|
LOCAL_STACK_SIZE.with(|val| val.set(STACK_SIZE));
|
2018-12-03 15:35:46 +01:00
|
|
|
let ini = (stealer, channel.clone(), wait, wait_mutex.clone(), deleting);
|
|
|
|
let future = future::loop_fn(ini, |(stealer, channel, wait, wait_mutex, deleting)| {
|
|
|
|
{
|
|
|
|
let mut lock = wait_mutex.lock();
|
|
|
|
if deleting.load(AtomicOrdering::Acquire) {
|
|
|
|
return Ok(Loop::Break(()));
|
|
|
|
}
|
|
|
|
wait.wait(&mut lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
while !deleting.load(AtomicOrdering::Acquire) {
|
|
|
|
match stealer.steal() {
|
|
|
|
deque::Steal::Data(work) => Worker::do_work(work, channel.clone()),
|
|
|
|
deque::Steal::Retry => {},
|
|
|
|
deque::Steal::Empty => break,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(Loop::Continue((stealer, channel, wait, wait_mutex, deleting)))
|
|
|
|
});
|
|
|
|
if let Err(()) = tokio::runtime::current_thread::block_on_all(future) {
|
|
|
|
error!(target: "ioworker", "error while executing future")
|
|
|
|
}
|
2016-02-10 12:50:27 +01:00
|
|
|
})
|
2016-01-21 17:21:51 +01:00
|
|
|
.expect("Error creating worker thread"));
|
|
|
|
worker
|
|
|
|
}
|
|
|
|
|
2018-05-09 08:49:34 +02:00
|
|
|
fn do_work<Message>(work: Work<Message>, channel: IoChannel<Message>) where Message: Send + Sync + 'static {
|
2016-01-21 17:21:51 +01:00
|
|
|
match work.work_type {
|
|
|
|
WorkType::Readable => {
|
2016-01-22 14:44:17 +01:00
|
|
|
work.handler.stream_readable(&IoContext::new(channel, work.handler_id), work.token);
|
2016-01-21 17:21:51 +01:00
|
|
|
},
|
|
|
|
WorkType::Writable => {
|
2016-01-22 14:44:17 +01:00
|
|
|
work.handler.stream_writable(&IoContext::new(channel, work.handler_id), work.token);
|
2016-01-21 17:21:51 +01:00
|
|
|
}
|
|
|
|
WorkType::Hup => {
|
2016-01-22 14:44:17 +01:00
|
|
|
work.handler.stream_hup(&IoContext::new(channel, work.handler_id), work.token);
|
2016-01-21 17:21:51 +01:00
|
|
|
}
|
|
|
|
WorkType::Timeout => {
|
2016-01-22 14:44:17 +01:00
|
|
|
work.handler.timeout(&IoContext::new(channel, work.handler_id), work.token);
|
2016-01-21 17:21:51 +01:00
|
|
|
}
|
|
|
|
WorkType::Message(message) => {
|
2018-05-09 08:49:34 +02:00
|
|
|
work.handler.message(&IoContext::new(channel, work.handler_id), &*message);
|
2016-01-21 17:21:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for Worker {
|
|
|
|
fn drop(&mut self) {
|
2016-04-06 23:45:19 +02:00
|
|
|
trace!(target: "shutdown", "[IoWorker] Closing...");
|
2018-08-22 16:01:07 +02:00
|
|
|
let _ = self.wait_mutex.lock();
|
2016-02-16 17:53:31 +01:00
|
|
|
self.deleting.store(true, AtomicOrdering::Release);
|
2016-01-21 17:21:51 +01:00
|
|
|
self.wait.notify_all();
|
2016-10-31 19:58:47 +01:00
|
|
|
if let Some(thread) = self.thread.take() {
|
|
|
|
thread.join().ok();
|
|
|
|
}
|
2016-04-06 23:45:19 +02:00
|
|
|
trace!(target: "shutdown", "[IoWorker] Closed");
|
2016-01-21 17:21:51 +01:00
|
|
|
}
|
|
|
|
}
|