Skip to content

Commit

Permalink
Change has_atomic_cas to no_atomic_cas to implement the first workaround
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e committed Dec 31, 2020
1 parent 665c32e commit c0e926c
Show file tree
Hide file tree
Showing 14 changed files with 259 additions and 32 deletions.
8 changes: 6 additions & 2 deletions futures-channel/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ fn main() {
}
};

if cfg.probe_expression("core::sync::atomic::AtomicPtr::<()>::compare_exchange") {
println!("cargo:rustc-cfg=has_atomic_cas");
// Note that this is `no_atomic_cas`, not `has_atomic_cas`. This allows to
// treat `cfg(target_has_atomic = "ptr")` as true when the build script
// doesn't run. This is needed for compatibility with non-cargo build
// systems that don't run build scripts.
if !cfg.probe_expression("core::sync::atomic::AtomicPtr::<()>::compare_exchange") {
println!("cargo:rustc-cfg=no_atomic_cas");
}
println!("cargo:rerun-if-changed=build.rs");
}
2 changes: 1 addition & 1 deletion futures-channel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

macro_rules! cfg_target_has_atomic {
($($item:item)*) => {$(
#[cfg(has_atomic_cas)]
#[cfg(not(no_atomic_cas))]
$item
)*};
}
Expand Down
8 changes: 6 additions & 2 deletions futures-core/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ fn main() {
}
};

if cfg.probe_expression("core::sync::atomic::AtomicPtr::<()>::compare_exchange") {
println!("cargo:rustc-cfg=has_atomic_cas");
// Note that this is `no_atomic_cas`, not `has_atomic_cas`. This allows to
// treat `cfg(target_has_atomic = "ptr")` as true when the build script
// doesn't run. This is needed for compatibility with non-cargo build
// systems that don't run build scripts.
if !cfg.probe_expression("core::sync::atomic::AtomicPtr::<()>::compare_exchange") {
println!("cargo:rustc-cfg=no_atomic_cas");
}
println!("cargo:rerun-if-changed=build.rs");
}
4 changes: 2 additions & 2 deletions futures-core/src/task/__internal/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#[cfg(has_atomic_cas)]
#[cfg(not(no_atomic_cas))]
mod atomic_waker;
#[cfg(has_atomic_cas)]
#[cfg(not(no_atomic_cas))]
pub use self::atomic_waker::AtomicWaker;
8 changes: 6 additions & 2 deletions futures-task/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ fn main() {
}
};

if cfg.probe_expression("core::sync::atomic::AtomicPtr::<()>::compare_exchange") {
println!("cargo:rustc-cfg=has_atomic_cas");
// Note that this is `no_atomic_cas`, not `has_atomic_cas`. This allows to
// treat `cfg(target_has_atomic = "ptr")` as true when the build script
// doesn't run. This is needed for compatibility with non-cargo build
// systems that don't run build scripts.
if !cfg.probe_expression("core::sync::atomic::AtomicPtr::<()>::compare_exchange") {
println!("cargo:rustc-cfg=no_atomic_cas");
}
println!("cargo:rerun-if-changed=build.rs");
}
2 changes: 1 addition & 1 deletion futures-task/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ extern crate alloc;

macro_rules! cfg_target_has_atomic {
($($item:item)*) => {$(
#[cfg(has_atomic_cas)]
#[cfg(not(no_atomic_cas))]
$item
)*};
}
Expand Down
207 changes: 207 additions & 0 deletions futures-task/src/spawn2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
use crate::{FutureObj, LocalFutureObj};
use core::fmt;
use std::{future::Future, pin::Pin};

/// The `Spawn` trait allows for pushing futures onto an executor that will
/// run them to completion.
pub trait Spawn {
type Handle;
/// An error that occurred during spawning.
type Error;

/// Spawns a future that will be run to completion.
///
/// # Errors
///
/// The executor may be unable to spawn tasks. Spawn errors should
/// represent relatively rare scenarios, such as the executor
/// having been shut down so that it is no longer able to accept
/// tasks.
fn spawn_boxed(
&self,
future: Pin<Box<dyn Future<Output = ()> + Send + 'static>>,
) -> Result<Self::Handle, Self::Error>;

/// Determines whether the executor is able to spawn new tasks.
///
/// This method will return `Ok` when the executor is *likely*
/// (but not guaranteed) to accept a subsequent spawn attempt.
/// Likewise, an `Err` return means that `spawn` is likely, but
/// not guaranteed, to yield an error.
#[inline]
fn status(&self) -> Result<(), Self::Error> {
Ok(())
}
}

/// The `LocalSpawn` is similar to [`Spawn`], but allows spawning futures
/// that don't implement `Send`.
pub trait LocalSpawn {
type Handle;
/// An error that occurred during spawning.
type Error;

/// Spawns a future that will be run to completion.
///
/// # Errors
///
/// The executor may be unable to spawn tasks. Spawn errors should
/// represent relatively rare scenarios, such as the executor
/// having been shut down so that it is no longer able to accept
/// tasks.
fn spawn_local_boxed(
&self,
future: Pin<Box<dyn Future<Output = ()> + Send + 'static>>,
) -> Result<Self::Handle, Self::Error>;

/// Determines whether the executor is able to spawn new tasks.
///
/// This method will return `Ok` when the executor is *likely*
/// (but not guaranteed) to accept a subsequent spawn attempt.
/// Likewise, an `Err` return means that `spawn` is likely, but
/// not guaranteed, to yield an error.
#[inline]
fn status_local(&self) -> Result<(), Self::Error> {
Ok(())
}
}

impl<Sp: ?Sized + Spawn> Spawn for &Sp {
fn spawn_boxed(
&self,
future: Pin<Box<dyn Future<Output = ()> + Send + 'static>>,
) -> Result<Self::Handle, Self::Error> {
Sp::spawn_obj(self, future)
}

fn status(&self) -> Result<(), Self::Error> {
Sp::status(self)
}
}

impl<Sp: ?Sized + Spawn> Spawn for &mut Sp {
fn spawn_boxed(
&self,
future: Pin<Box<dyn Future<Output = ()> + Send + 'static>>,
) -> Result<Self::Handle, Self::Error> {
Sp::spawn_obj(self, future)
}

fn status(&self) -> Result<(), Self::Error> {
Sp::status(self)
}
}

impl<Sp: ?Sized + LocalSpawn> LocalSpawn for &Sp {
fn spawn_local_boxed(
&self,
future: Pin<Box<dyn Future<Output = ()> + Send + 'static>>,
) -> Result<Self::Handle, Self::Error> {
Sp::spawn_local_boxed(self, future)
}

fn status_local(&self) -> Result<(), Self::Error> {
Sp::status_local(self)
}
}

impl<Sp: ?Sized + LocalSpawn> LocalSpawn for &mut Sp {
fn spawn_local_boxed(
&self,
future: Pin<Box<dyn Future<Output = ()> + Send + 'static>>,
) -> Result<Self::Handle, Self::Error> {
Sp::spawn_local_boxed(self, future)
}

fn status_local(&self) -> Result<(), Self::Error> {
Sp::status_local(self)
}
}

#[cfg(feature = "alloc")]
mod if_alloc {
use super::*;
use alloc::{boxed::Box, rc::Rc};

impl<Sp: ?Sized + Spawn> Spawn for Box<Sp> {
fn spawn_boxed(
&self,
future: Pin<Box<dyn Future<Output = ()> + Send + 'static>>,
) -> Result<Self::Handle, Self::Error> {
(**self).spawn_obj(future)
}

fn status(&self) -> Result<(), Self::Error> {
(**self).status()
}
}

impl<Sp: ?Sized + LocalSpawn> LocalSpawn for Box<Sp> {
fn spawn_local_boxed(
&self,
future: Pin<Box<dyn Future<Output = ()> + Send + 'static>>,
) -> Result<Self::Handle, Self::Error> {
(**self).spawn_local_boxed(future)
}

fn status_local(&self) -> Result<(), Self::Error> {
(**self).status_local()
}
}

impl<Sp: ?Sized + Spawn> Spawn for Rc<Sp> {
fn spawn_boxed(
&self,
future: Pin<Box<dyn Future<Output = ()> + Send + 'static>>,
) -> Result<Self::Handle, Self::Error> {
(**self).spawn_obj(future)
}

fn status(&self) -> Result<(), Self::Error> {
(**self).status()
}
}

impl<Sp: ?Sized + LocalSpawn> LocalSpawn for Rc<Sp> {
fn spawn_local_boxed(
&self,
future: Pin<Box<dyn Future<Output = ()> + Send + 'static>>,
) -> Result<Self::Handle, Self::Error> {
(**self).spawn_local_boxed(future)
}

fn status_local(&self) -> Result<(), Self::Error> {
(**self).status_local()
}
}

cfg_target_has_atomic! {
use alloc::sync::Arc;

impl<Sp: ?Sized + Spawn> Spawn for Arc<Sp> {
fn spawn_boxed(
&self,
future: Pin<Box<dyn Future<Output = ()> + Send + 'static>>,
) -> Result<Self::Handle, Self::Error> {
(**self).spawn_obj(future)
}

fn status(&self) -> Result<(), Self::Error> {
(**self).status()
}
}

impl<Sp: ?Sized + LocalSpawn> LocalSpawn for Arc<Sp> {
fn spawn_local_boxed(
&self,
future: Pin<Box<dyn Future<Output = ()> + Send + 'static>>,
) -> Result<Self::Handle, Self::Error> {
(**self).spawn_local_boxed(future)
}

fn status_local(&self) -> Result<(), Self::Error> {
(**self).status_local()
}
}
}
}
8 changes: 6 additions & 2 deletions futures-util/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ fn main() {
}
};

if cfg.probe_expression("core::sync::atomic::AtomicPtr::<()>::compare_exchange") {
println!("cargo:rustc-cfg=has_atomic_cas");
// Note that this is `no_atomic_cas`, not `has_atomic_cas`. This allows to
// treat `cfg(target_has_atomic = "ptr")` as true when the build script
// doesn't run. This is needed for compatibility with non-cargo build
// systems that don't run build scripts.
if !cfg.probe_expression("core::sync::atomic::AtomicPtr::<()>::compare_exchange") {
println!("cargo:rustc-cfg=no_atomic_cas");
}
println!("cargo:rerun-if-changed=build.rs");
}
2 changes: 1 addition & 1 deletion futures-util/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub mod __private {

macro_rules! cfg_target_has_atomic {
($($item:item)*) => {$(
#[cfg(has_atomic_cas)]
#[cfg(not(no_atomic_cas))]
$item
)*};
}
Expand Down
6 changes: 3 additions & 3 deletions futures-util/src/stream/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ pub use self::stream::ReadyChunks;
#[cfg_attr(docsrs, doc(cfg(feature = "sink")))]
pub use self::stream::Forward;

#[cfg(has_atomic_cas)]
#[cfg(not(no_atomic_cas))]
#[cfg(feature = "alloc")]
pub use self::stream::{BufferUnordered, Buffered, ForEachConcurrent};

#[cfg(has_atomic_cas)]
#[cfg(not(no_atomic_cas))]
#[cfg(feature = "sink")]
#[cfg_attr(docsrs, doc(cfg(feature = "sink")))]
#[cfg(feature = "alloc")]
Expand All @@ -53,7 +53,7 @@ pub use self::try_stream::{
#[cfg(feature = "std")]
pub use self::try_stream::IntoAsyncRead;

#[cfg(has_atomic_cas)]
#[cfg(not(no_atomic_cas))]
#[cfg(feature = "alloc")]
pub use self::try_stream::{TryBufferUnordered, TryBuffered, TryForEachConcurrent};

Expand Down
8 changes: 4 additions & 4 deletions futures-util/src/stream/stream/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -917,7 +917,7 @@ pub trait StreamExt: Stream {
/// fut.await;
/// # })
/// ```
#[cfg(has_atomic_cas)]
#[cfg(not(no_atomic_cas))]
#[cfg(feature = "alloc")]
fn for_each_concurrent<Fut, F>(
self,
Expand Down Expand Up @@ -1140,7 +1140,7 @@ pub trait StreamExt: Stream {
///
/// This method is only available when the `std` or `alloc` feature of this
/// library is activated, and it is activated by default.
#[cfg(has_atomic_cas)]
#[cfg(not(no_atomic_cas))]
#[cfg(feature = "alloc")]
fn buffered(self, n: usize) -> Buffered<Self>
where
Expand Down Expand Up @@ -1185,7 +1185,7 @@ pub trait StreamExt: Stream {
/// assert_eq!(buffered.next().await, None);
/// # Ok::<(), i32>(()) }).unwrap();
/// ```
#[cfg(has_atomic_cas)]
#[cfg(not(no_atomic_cas))]
#[cfg(feature = "alloc")]
fn buffer_unordered(self, n: usize) -> BufferUnordered<Self>
where
Expand Down Expand Up @@ -1349,7 +1349,7 @@ pub trait StreamExt: Stream {
/// library is activated, and it is activated by default.
#[cfg(feature = "sink")]
#[cfg_attr(docsrs, doc(cfg(feature = "sink")))]
#[cfg(has_atomic_cas)]
#[cfg(not(no_atomic_cas))]
#[cfg(feature = "alloc")]
fn split<Item>(self) -> (SplitSink<Self, Item>, SplitStream<Self>)
where
Expand Down
6 changes: 3 additions & 3 deletions futures-util/src/stream/try_stream/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ pub trait TryStreamExt: TryStream {
/// assert_eq!(Err(oneshot::Canceled), fut.await);
/// # })
/// ```
#[cfg(has_atomic_cas)]
#[cfg(not(no_atomic_cas))]
#[cfg(feature = "alloc")]
fn try_for_each_concurrent<Fut, F>(
self,
Expand Down Expand Up @@ -836,7 +836,7 @@ pub trait TryStreamExt: TryStream {
/// assert_eq!(buffered.next().await, Some(Err("error in the stream")));
/// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap();
/// ```
#[cfg(has_atomic_cas)]
#[cfg(not(no_atomic_cas))]
#[cfg(feature = "alloc")]
fn try_buffer_unordered(self, n: usize) -> TryBufferUnordered<Self>
where
Expand Down Expand Up @@ -912,7 +912,7 @@ pub trait TryStreamExt: TryStream {
/// assert_eq!(buffered.next().await, Some(Err("error in the stream")));
/// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap();
/// ```
#[cfg(has_atomic_cas)]
#[cfg(not(no_atomic_cas))]
#[cfg(feature = "alloc")]
fn try_buffered(self, n: usize) -> TryBuffered<Self>
where
Expand Down
Loading

0 comments on commit c0e926c

Please sign in to comment.