mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-09-09 00:00:08 +02:00
This patch adds experimental async/await support to Tokio. It does this by adding feature flags to existing libs only where necessary in order to add nightly specific code (mostly `Unpin` implementations). It then provides a new crate: `tokio-async-await` which is a shim layer on top of `tokio`. The `tokio-async-await` crate is expected to look exactly like `tokio` does, but with async / await support. This strategy reduces the amount of cfg guarding in the main libraries. This patch also adds `tokio-channel`, which is copied from futures-rs 0.1 and adds the necessary `Unpin` implementations. In general, futures 0.1 is mostly unmaintained, so it will make sense for Tokio to take over maintainership of key components regardless of async / await support.
106 lines
3.1 KiB
Rust
106 lines
3.1 KiB
Rust
//! A "mutex" which only supports `try_lock`
|
|
//!
|
|
//! As a futures library the eventual call to an event loop should be the only
|
|
//! thing that ever blocks, so this is assisted with a fast user-space
|
|
//! implementation of a lock that can only have a `try_lock` operation.
|
|
|
|
use std::cell::UnsafeCell;
|
|
use std::ops::{Deref, DerefMut};
|
|
use std::sync::atomic::Ordering::SeqCst;
|
|
use std::sync::atomic::AtomicBool;
|
|
|
|
/// A "mutex" around a value, similar to `std::sync::Mutex<T>`.
|
|
///
|
|
/// This lock only supports the `try_lock` operation, however, and does not
|
|
/// implement poisoning.
|
|
#[derive(Debug)]
|
|
pub struct Lock<T> {
|
|
locked: AtomicBool,
|
|
data: UnsafeCell<T>,
|
|
}
|
|
|
|
/// Sentinel representing an acquired lock through which the data can be
|
|
/// accessed.
|
|
pub struct TryLock<'a, T: 'a> {
|
|
__ptr: &'a Lock<T>,
|
|
}
|
|
|
|
// The `Lock` structure is basically just a `Mutex<T>`, and these two impls are
|
|
// intended to mirror the standard library's corresponding impls for `Mutex<T>`.
|
|
//
|
|
// If a `T` is sendable across threads, so is the lock, and `T` must be sendable
|
|
// across threads to be `Sync` because it allows mutable access from multiple
|
|
// threads.
|
|
unsafe impl<T: Send> Send for Lock<T> {}
|
|
unsafe impl<T: Send> Sync for Lock<T> {}
|
|
|
|
impl<T> Lock<T> {
|
|
/// Creates a new lock around the given value.
|
|
pub fn new(t: T) -> Lock<T> {
|
|
Lock {
|
|
locked: AtomicBool::new(false),
|
|
data: UnsafeCell::new(t),
|
|
}
|
|
}
|
|
|
|
/// Attempts to acquire this lock, returning whether the lock was acquired or
|
|
/// not.
|
|
///
|
|
/// If `Some` is returned then the data this lock protects can be accessed
|
|
/// through the sentinel. This sentinel allows both mutable and immutable
|
|
/// access.
|
|
///
|
|
/// If `None` is returned then the lock is already locked, either elsewhere
|
|
/// on this thread or on another thread.
|
|
pub fn try_lock(&self) -> Option<TryLock<T>> {
|
|
if !self.locked.swap(true, SeqCst) {
|
|
Some(TryLock { __ptr: self })
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, T> Deref for TryLock<'a, T> {
|
|
type Target = T;
|
|
fn deref(&self) -> &T {
|
|
// The existence of `TryLock` represents that we own the lock, so we
|
|
// can safely access the data here.
|
|
unsafe { &*self.__ptr.data.get() }
|
|
}
|
|
}
|
|
|
|
impl<'a, T> DerefMut for TryLock<'a, T> {
|
|
fn deref_mut(&mut self) -> &mut T {
|
|
// The existence of `TryLock` represents that we own the lock, so we
|
|
// can safely access the data here.
|
|
//
|
|
// Additionally, we're the *only* `TryLock` in existence so mutable
|
|
// access should be ok.
|
|
unsafe { &mut *self.__ptr.data.get() }
|
|
}
|
|
}
|
|
|
|
impl<'a, T> Drop for TryLock<'a, T> {
|
|
fn drop(&mut self) {
|
|
self.__ptr.locked.store(false, SeqCst);
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::Lock;
|
|
|
|
#[test]
|
|
fn smoke() {
|
|
let a = Lock::new(1);
|
|
let mut a1 = a.try_lock().unwrap();
|
|
assert!(a.try_lock().is_none());
|
|
assert_eq!(*a1, 1);
|
|
*a1 = 2;
|
|
drop(a1);
|
|
assert_eq!(*a.try_lock().unwrap(), 2);
|
|
assert_eq!(*a.try_lock().unwrap(), 2);
|
|
}
|
|
}
|