blob: 9a77a2aef95dbd10af46d3f88169fbf9f49e5d84 [file] [log] [blame]
#![cfg_attr(feature = "use_std", allow(dead_code))]
use core::marker;
use core::mem;
use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
use core::sync::atomic::Ordering::{SeqCst, Relaxed};
use super::{BorrowedTask, NotifyHandle};
pub struct LocalKey;
pub struct LocalMap;
pub fn local_map() -> LocalMap { LocalMap }
#[derive(Copy, Clone)]
pub struct BorrowedEvents<'a>(marker::PhantomData<&'a ()>);
#[derive(Copy, Clone)]
pub struct BorrowedUnpark<'a> {
f: &'a Fn() -> NotifyHandle,
id: usize,
}
pub struct TaskUnpark {
handle: NotifyHandle,
id: usize,
}
#[derive(Clone)]
pub struct UnparkEvents;
impl<'a> BorrowedEvents<'a> {
pub fn new() -> BorrowedEvents<'a> {
BorrowedEvents(marker::PhantomData)
}
pub fn to_owned(&self) -> UnparkEvents {
UnparkEvents
}
}
impl<'a> BorrowedUnpark<'a> {
#[inline]
pub fn new(f: &'a Fn() -> NotifyHandle, id: usize) -> BorrowedUnpark<'a> {
BorrowedUnpark { f: f, id: id }
}
#[inline]
pub fn to_owned(&self) -> TaskUnpark {
let handle = (self.f)();
let id = handle.clone_id(self.id);
TaskUnpark { handle: handle, id: id }
}
}
impl UnparkEvents {
pub fn notify(&self) {}
pub fn will_notify(&self, _other: &BorrowedEvents) -> bool {
true
}
}
impl TaskUnpark {
pub fn notify(&self) {
self.handle.notify(self.id);
}
pub fn will_notify(&self, other: &BorrowedUnpark) -> bool {
self.id == other.id && self.handle.inner == (other.f)().inner
}
}
impl Clone for TaskUnpark {
fn clone(&self) -> TaskUnpark {
let handle = self.handle.clone();
let id = handle.clone_id(self.id);
TaskUnpark { handle: handle, id: id }
}
}
impl Drop for TaskUnpark {
fn drop(&mut self) {
self.handle.drop_id(self.id);
}
}
static GET: AtomicUsize = ATOMIC_USIZE_INIT;
static SET: AtomicUsize = ATOMIC_USIZE_INIT;
/// Initialize the `futures` task system.
///
/// This function is an unsafe low-level implementation detail typically only
/// used by crates using `futures` in `no_std` context. Users of this crate
/// who also use the standard library never need to invoke this function.
///
/// The task system in the `futures` crate relies on some notion of "local
/// storage" for the running thread and/or context. The `task::current` function
/// can get invoked in any context, for example, and needs to be able to return
/// a `Task`. Typically with the standard library this is supported with
/// thread-local-storage, but this is not available in `no_std` contexts!
///
/// This function is provided to allow `no_std` contexts to continue to be able
/// to use the standard task system in this crate. The functions provided here
/// will be used as-if they were thread-local-storage getters/setters. The `get`
/// function provided is used to retrieve the current thread-local value of the
/// task system's pointer, returning null if not initialized. The `set` function
/// updates the value of the pointer.
///
/// # Return value
///
/// This function will return whether initialization succeeded or not. This
/// function can be called concurrently and only the first invocation will
/// succeed. If `false` is returned then the `get` and `set` pointers provided
/// were *not* registered for use with the task system, but if `true` was
/// provided then they will be called when the task system is used.
///
/// Note that while safe to call concurrently it's recommended to still perform
/// external synchronization when calling this function. This task system is
/// not guaranteed to be ready to go until a call to this function returns
/// `true`. In other words, if you call this function and see `false`, the
/// task system may not be ready to go as another thread may still be calling
/// `init`.
///
/// # Unsafety
///
/// This function is unsafe due to the requirements on the behavior of the
/// `get` and `set` functions. The pointers returned from these functions must
/// reflect the semantics specified above and must also be thread-local,
/// depending on the definition of a "thread" in the calling context.
pub unsafe fn init(get: fn() -> *mut u8, set: fn(*mut u8)) -> bool {
if GET.compare_exchange(0, get as usize, SeqCst, SeqCst).is_ok() {
SET.store(set as usize, SeqCst);
true
} else {
false
}
}
#[inline]
pub fn get_ptr() -> Option<*mut u8> {
match GET.load(Relaxed) {
0 => None,
n => Some(unsafe { mem::transmute::<usize, fn() -> *mut u8>(n)() }),
}
}
#[cfg(feature = "use_std")]
#[inline]
pub fn is_get_ptr(f: usize) -> bool {
GET.load(Relaxed) == f
}
pub fn set<'a, F, R>(task: &BorrowedTask<'a>, f: F) -> R
where F: FnOnce() -> R
{
let set = match SET.load(Relaxed) {
0 => panic!("not initialized"),
n => unsafe { mem::transmute::<usize, fn(*mut u8)>(n) },
};
struct Reset(fn(*mut u8), *mut u8);
impl Drop for Reset {
#[inline]
fn drop(&mut self) {
(self.0)(self.1);
}
}
let _reset = Reset(set, get_ptr().unwrap());
set(task as *const _ as *mut u8);
f()
}