2018-04-04 13:30:54 -07:00
|
|
|
use pool::Pool;
|
2018-03-28 01:56:21 +03:00
|
|
|
use task::Task;
|
|
|
|
|
|
|
|
|
|
use std::mem;
|
2018-04-15 12:29:22 -07:00
|
|
|
use std::ops;
|
2018-10-15 22:24:00 +02:00
|
|
|
use std::sync::Arc;
|
2018-03-28 01:56:21 +03:00
|
|
|
|
|
|
|
|
use futures::executor::Notify;
|
|
|
|
|
|
|
|
|
|
/// Implements the future `Notify` API.
|
|
|
|
|
///
|
|
|
|
|
/// This is how external events are able to signal the task, informing it to try
|
|
|
|
|
/// to poll the future again.
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub(crate) struct Notifier {
|
2018-11-20 20:05:14 +01:00
|
|
|
pub pool: Arc<Pool>,
|
2018-03-28 01:56:21 +03:00
|
|
|
}
|
|
|
|
|
|
2018-04-15 12:29:22 -07:00
|
|
|
/// A guard that ensures that the inner value gets forgotten.
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
struct Forget<T>(Option<T>);
|
|
|
|
|
|
2018-03-28 01:56:21 +03:00
|
|
|
impl Notify for Notifier {
|
|
|
|
|
fn notify(&self, id: usize) {
|
|
|
|
|
trace!("Notifier::notify; id=0x{:x}", id);
|
|
|
|
|
|
2018-04-05 10:57:05 -07:00
|
|
|
unsafe {
|
|
|
|
|
let ptr = id as *const Task;
|
2018-03-28 01:56:21 +03:00
|
|
|
|
2018-04-15 12:29:22 -07:00
|
|
|
// We did not actually take ownership of the `Arc` in this function
|
|
|
|
|
// so we must ensure that the Arc is forgotten.
|
|
|
|
|
let task = Forget::new(Arc::from_raw(ptr));
|
|
|
|
|
|
|
|
|
|
// TODO: Unify this with Task::notify
|
2018-04-05 10:57:05 -07:00
|
|
|
if task.schedule() {
|
|
|
|
|
// TODO: Check if the pool is still running
|
|
|
|
|
//
|
|
|
|
|
// Bump the ref count
|
|
|
|
|
let task = task.clone();
|
2018-03-28 01:56:21 +03:00
|
|
|
|
2018-11-20 20:05:14 +01:00
|
|
|
let _ = self.pool.submit(task, &self.pool);
|
2018-04-05 10:57:05 -07:00
|
|
|
}
|
2018-03-28 01:56:21 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn clone_id(&self, id: usize) -> usize {
|
2018-04-05 10:57:05 -07:00
|
|
|
let ptr = id as *const Task;
|
|
|
|
|
|
|
|
|
|
// This function doesn't actually get a strong ref to the task here.
|
|
|
|
|
// However, the only method we have to convert a raw pointer -> &Arc<T>
|
|
|
|
|
// is to call `Arc::from_raw` which returns a strong ref. So, to
|
|
|
|
|
// maintain the invariants, `t1` has to be forgotten. This prevents the
|
|
|
|
|
// ref count from being decremented.
|
2018-04-15 12:29:22 -07:00
|
|
|
let t1 = Forget::new(unsafe { Arc::from_raw(ptr) });
|
2018-04-05 10:57:05 -07:00
|
|
|
|
2018-04-15 12:29:22 -07:00
|
|
|
// The clone is forgotten so that the fn exits without decrementing the ref
|
2018-04-05 10:57:05 -07:00
|
|
|
// count. The caller of `clone_id` ensures that `drop_id` is called when
|
|
|
|
|
// the ref count needs to be decremented.
|
2018-04-15 12:29:22 -07:00
|
|
|
let _ = Forget::new(t1.clone());
|
2018-03-28 01:56:21 +03:00
|
|
|
|
|
|
|
|
id
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn drop_id(&self, id: usize) {
|
|
|
|
|
unsafe {
|
2018-04-05 10:57:05 -07:00
|
|
|
let ptr = id as *const Task;
|
|
|
|
|
let _ = Arc::from_raw(ptr);
|
2018-03-28 01:56:21 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-04-15 12:29:22 -07:00
|
|
|
|
|
|
|
|
// ===== impl Forget =====
|
|
|
|
|
|
|
|
|
|
impl<T> Forget<T> {
|
|
|
|
|
fn new(t: T) -> Self {
|
|
|
|
|
Forget(Some(t))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> ops::Deref for Forget<T> {
|
|
|
|
|
type Target = T;
|
|
|
|
|
|
|
|
|
|
fn deref(&self) -> &T {
|
|
|
|
|
self.0.as_ref().unwrap()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> Drop for Forget<T> {
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
mem::forget(self.0.take());
|
|
|
|
|
}
|
|
|
|
|
}
|