aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-03-10 01:04:21 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-03-10 01:04:21 +0000
commit5b1ccf8bd59399abe7e42fc39dfc6c261f370458 (patch)
treea8c0195dcd49ed82252eacb02eecc46b2bc3cc63
parent78bfcf8b89596afcc5817ba529eb8676d643bf29 (diff)
parente12d2cfcff2456cbe3c7ff1974ff288b7c1c381e (diff)
downloadasync-task-android13-d1-s2-release.tar.gz
Change-Id: Ic36f00da4cf43fc9e366f08c90d89ecbfa86c12c
-rw-r--r--.cargo_vcs_info.json6
-rw-r--r--.github/workflows/build-and-test.yaml50
-rw-r--r--.github/workflows/lint.yaml24
-rw-r--r--.github/workflows/security.yaml17
-rw-r--r--Android.bp2
-rw-r--r--CHANGELOG.md4
-rw-r--r--Cargo.toml48
-rw-r--r--Cargo.toml.orig31
-rw-r--r--METADATA14
-rw-r--r--src/lib.rs2
-rw-r--r--src/runnable.rs2
-rw-r--r--src/task.rs164
-rw-r--r--tests/basic.rs2
-rw-r--r--tests/cancel.rs2
-rw-r--r--tests/join.rs2
-rw-r--r--tests/panic.rs2
-rw-r--r--tests/ready.rs2
-rw-r--r--tests/waker_panic.rs9
-rw-r--r--tests/waker_pending.rs2
-rw-r--r--tests/waker_ready.rs2
20 files changed, 250 insertions, 137 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..afec74b
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+ "git": {
+ "sha1": "e6daa4ff3caadb73c7a7ddc40034fb02430ccec8"
+ },
+ "path_in_vcs": ""
+} \ No newline at end of file
diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml
deleted file mode 100644
index d98cd81..0000000
--- a/.github/workflows/build-and-test.yaml
+++ /dev/null
@@ -1,50 +0,0 @@
-name: Build and test
-
-on:
- push:
- branches:
- - master
- pull_request:
-
-jobs:
- build_and_test:
- runs-on: ${{ matrix.os }}
- strategy:
- fail-fast: false
- matrix:
- os: [ubuntu-latest]
- rust: [nightly, beta, stable]
- steps:
- - uses: actions/checkout@v2
-
- - name: Install latest ${{ matrix.rust }}
- uses: actions-rs/toolchain@v1
- with:
- toolchain: ${{ matrix.rust }}
- profile: minimal
- override: true
-
- - name: Install valgrind
- run: |
- sudo apt-get update
- sudo apt-get install -y valgrind
-
- - name: Run cargo check
- uses: actions-rs/cargo@v1
- with:
- command: check
- args: --all --bins --examples --tests --all-features
-
- - name: Run cargo check (no_std)
- uses: actions-rs/cargo@v1
- with:
- command: check
- args: --all --no-default-features
-
- - name: Run cargo test
- uses: actions-rs/cargo@v1
- with:
- command: test
- args: -- --test-threads=1
- env:
- CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER: "valgrind --leak-check=full --error-exitcode=1"
diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml
deleted file mode 100644
index e134a54..0000000
--- a/.github/workflows/lint.yaml
+++ /dev/null
@@ -1,24 +0,0 @@
-name: Lint
-
-on:
- push:
- branches:
- - master
- pull_request:
-
-jobs:
- clippy:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
-
- - uses: actions-rs/toolchain@v1
- with:
- toolchain: stable
- profile: minimal
- components: clippy
-
- - uses: actions-rs/clippy-check@v1
- with:
- token: ${{ secrets.GITHUB_TOKEN }}
- args: --all-features -- -W clippy::all
diff --git a/.github/workflows/security.yaml b/.github/workflows/security.yaml
deleted file mode 100644
index c4f7947..0000000
--- a/.github/workflows/security.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-name: Security audit
-
-on:
- push:
- branches:
- - master
- pull_request:
-
-jobs:
- security_audit:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
-
- - uses: actions-rs/audit-check@v1
- with:
- token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/Android.bp b/Android.bp
index 0b36523..419d97d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -42,7 +42,7 @@ rust_library {
host_supported: true,
crate_name: "async_task",
cargo_env_compat: true,
- cargo_pkg_version: "4.0.3",
+ cargo_pkg_version: "4.1.0",
srcs: ["src/lib.rs"],
edition: "2018",
features: [
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6bdcc73..668bd12 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# Version 4.1.0
+
+- Add `FallibleTask`. (#21)
+
# Version 4.0.3
- Document the return value of `Runnable::run()` better.
diff --git a/Cargo.toml b/Cargo.toml
index c50b366..f563dc6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,23 +1,45 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
[package]
+edition = "2018"
+rust-version = "1.39"
name = "async-task"
-version = "4.0.3"
+version = "4.1.0"
authors = ["Stjepan Glavina <stjepang@gmail.com>"]
-edition = "2018"
-license = "Apache-2.0 OR MIT"
-repository = "https://github.com/smol-rs/async-task"
-homepage = "https://github.com/smol-rs/async-task"
-documentation = "https://docs.rs/async-task"
+exclude = ["/.*"]
description = "Task abstraction for building executors"
keywords = ["futures", "task", "executor", "spawn"]
categories = ["asynchronous", "concurrency", "no-std"]
+license = "Apache-2.0 OR MIT"
+repository = "https://github.com/smol-rs/async-task"
+[dev-dependencies.atomic-waker]
+version = "1"
+
+[dev-dependencies.easy-parallel]
+version = "3"
+
+[dev-dependencies.flaky_test]
+version = "0.1"
+
+[dev-dependencies.flume]
+version = "0.10"
+default-features = false
+
+[dev-dependencies.once_cell]
+version = "1"
+
+[dev-dependencies.smol]
+version = "1"
[features]
default = ["std"]
std = []
-
-[dev-dependencies]
-atomic-waker = "1.0.0"
-easy-parallel = "3.1.0"
-flume = { version = "0.10", default-features = false }
-once_cell = "1.4.1"
-smol = "1.0.1"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..b1ae509
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,31 @@
+[package]
+name = "async-task"
+# When publishing a new version:
+# - Update CHANGELOG.md
+# - Create "v4.x.y" git tag
+version = "4.1.0"
+authors = ["Stjepan Glavina <stjepang@gmail.com>"]
+edition = "2018"
+rust-version = "1.39"
+license = "Apache-2.0 OR MIT"
+repository = "https://github.com/smol-rs/async-task"
+description = "Task abstraction for building executors"
+keywords = ["futures", "task", "executor", "spawn"]
+categories = ["asynchronous", "concurrency", "no-std"]
+exclude = ["/.*"]
+
+[features]
+default = ["std"]
+std = []
+
+[dev-dependencies]
+atomic-waker = "1"
+easy-parallel = "3"
+flaky_test = "0.1"
+flume = { version = "0.10", default-features = false }
+once_cell = "1"
+smol = "1"
+
+# rewrite dependencies to use the this version of async-task when running tests
+[patch.crates-io]
+async-task = { path = "." }
diff --git a/METADATA b/METADATA
index 463f005..23c5a33 100644
--- a/METADATA
+++ b/METADATA
@@ -1,7 +1,5 @@
name: "async_task"
-description:
- "Task abstraction for building executors (in rust)."
-
+description: "Task abstraction for building executors"
third_party {
url {
type: HOMEPAGE
@@ -9,9 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/async-task/async-task-4.0.3.crate"
+ value: "https://static.crates.io/crates/async_task/async_task-4.1.0.crate"
}
- version: "4.0.3"
- last_upgrade_date { year: 2021 month: 2 day: 5 }
+ version: "4.1.0"
license_type: NOTICE
+ last_upgrade_date {
+ year: 2022
+ month: 3
+ day: 1
+ }
}
diff --git a/src/lib.rs b/src/lib.rs
index 852696e..4a868bf 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -82,7 +82,7 @@ mod task;
mod utils;
pub use crate::runnable::{spawn, spawn_unchecked, Runnable};
-pub use crate::task::Task;
+pub use crate::task::{FallibleTask, Task};
#[cfg(feature = "std")]
pub use crate::runnable::spawn_local;
diff --git a/src/runnable.rs b/src/runnable.rs
index adecbcb..cb70ef3 100644
--- a/src/runnable.rs
+++ b/src/runnable.rs
@@ -147,7 +147,7 @@ where
/// This function is same as [`spawn()`], except it does not require [`Send`], [`Sync`], and
/// `'static` on `future` and `schedule`.
///
-/// Safety requirements:
+/// # Safety
///
/// - If `future` is not [`Send`], its [`Runnable`] must be used and dropped on the original
/// thread.
diff --git a/src/task.rs b/src/task.rs
index b9c251f..fff918c 100644
--- a/src/task.rs
+++ b/src/task.rs
@@ -124,18 +124,56 @@ impl<T> Task<T> {
pub async fn cancel(self) -> Option<T> {
let mut this = self;
this.set_canceled();
+ this.fallible().await
+ }
- struct Fut<T>(Task<T>);
-
- impl<T> Future for Fut<T> {
- type Output = Option<T>;
-
- fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
- self.0.poll_task(cx)
- }
- }
-
- Fut(this).await
+ /// Converts this task into a [`FallibleTask`].
+ ///
+ /// Like [`Task`], a fallible task will poll the task's output until it is
+ /// completed or cancelled due to its [`Runnable`][`super::Runnable`] being
+ /// dropped without being run. Resolves to the task's output when completed,
+ /// or [`None`] if it didn't complete.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use smol::{future, Executor};
+ /// use std::thread;
+ ///
+ /// let ex = Executor::new();
+ ///
+ /// // Spawn a future onto the executor.
+ /// let task = ex.spawn(async {
+ /// println!("Hello from a task!");
+ /// 1 + 2
+ /// })
+ /// .fallible();
+ ///
+ /// // Run an executor thread.
+ /// thread::spawn(move || future::block_on(ex.run(future::pending::<()>())));
+ ///
+ /// // Wait for the task's output.
+ /// assert_eq!(future::block_on(task), Some(3));
+ /// ```
+ ///
+ /// ```
+ /// use smol::future;
+ ///
+ /// // Schedule function which drops the runnable without running it.
+ /// let schedule = move |runnable| drop(runnable);
+ ///
+ /// // Create a task with the future and the schedule function.
+ /// let (runnable, task) = async_task::spawn(async {
+ /// println!("Hello from a task!");
+ /// 1 + 2
+ /// }, schedule);
+ /// runnable.schedule();
+ ///
+ /// // Wait for the task's output.
+ /// assert_eq!(future::block_on(task.fallible()), None);
+ /// ```
+ pub fn fallible(self) -> FallibleTask<T> {
+ FallibleTask { task: self }
}
/// Puts the task in canceled state.
@@ -351,6 +389,12 @@ impl<T> Task<T> {
}
}
}
+
+ fn header(&self) -> &Header {
+ let ptr = self.ptr.as_ptr();
+ let header = ptr as *const Header;
+ unsafe { &*header }
+ }
}
impl<T> Drop for Task<T> {
@@ -373,11 +417,101 @@ impl<T> Future for Task<T> {
impl<T> fmt::Debug for Task<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let ptr = self.ptr.as_ptr();
- let header = ptr as *const Header;
-
f.debug_struct("Task")
- .field("header", unsafe { &(*header) })
+ .field("header", self.header())
+ .finish()
+ }
+}
+
+/// A spawned task with a fallible response.
+///
+/// This type behaves like [`Task`], however it produces an `Option<T>` when
+/// polled and will return `None` if the executor dropped its
+/// [`Runnable`][`super::Runnable`] without being run.
+///
+/// This can be useful to avoid the panic produced when polling the `Task`
+/// future if the executor dropped its `Runnable`.
+#[must_use = "tasks get canceled when dropped, use `.detach()` to run them in the background"]
+pub struct FallibleTask<T> {
+ task: Task<T>,
+}
+
+impl<T> FallibleTask<T> {
+ /// Detaches the task to let it keep running in the background.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use smol::{Executor, Timer};
+ /// use std::time::Duration;
+ ///
+ /// let ex = Executor::new();
+ ///
+ /// // Spawn a deamon future.
+ /// ex.spawn(async {
+ /// loop {
+ /// println!("I'm a daemon task looping forever.");
+ /// Timer::after(Duration::from_secs(1)).await;
+ /// }
+ /// })
+ /// .fallible()
+ /// .detach();
+ /// ```
+ pub fn detach(self) {
+ self.task.detach()
+ }
+
+ /// Cancels the task and waits for it to stop running.
+ ///
+ /// Returns the task's output if it was completed just before it got canceled, or [`None`] if
+ /// it didn't complete.
+ ///
+ /// While it's possible to simply drop the [`Task`] to cancel it, this is a cleaner way of
+ /// canceling because it also waits for the task to stop running.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use smol::{future, Executor, Timer};
+ /// use std::thread;
+ /// use std::time::Duration;
+ ///
+ /// let ex = Executor::new();
+ ///
+ /// // Spawn a deamon future.
+ /// let task = ex.spawn(async {
+ /// loop {
+ /// println!("Even though I'm in an infinite loop, you can still cancel me!");
+ /// Timer::after(Duration::from_secs(1)).await;
+ /// }
+ /// })
+ /// .fallible();
+ ///
+ /// // Run an executor thread.
+ /// thread::spawn(move || future::block_on(ex.run(future::pending::<()>())));
+ ///
+ /// future::block_on(async {
+ /// Timer::after(Duration::from_secs(3)).await;
+ /// task.cancel().await;
+ /// });
+ /// ```
+ pub async fn cancel(self) -> Option<T> {
+ self.task.cancel().await
+ }
+}
+
+impl<T> Future for FallibleTask<T> {
+ type Output = Option<T>;
+
+ fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+ self.task.poll_task(cx)
+ }
+}
+
+impl<T> fmt::Debug for FallibleTask<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("FallibleTask")
+ .field("header", self.task.header())
.finish()
}
}
diff --git a/tests/basic.rs b/tests/basic.rs
index 1439e16..c223043 100644
--- a/tests/basic.rs
+++ b/tests/basic.rs
@@ -64,7 +64,7 @@ macro_rules! schedule {
let guard = Guard(Box::new(0));
move |_runnable| {
- &guard;
+ let _ = &guard;
$sched.fetch_add(1, Ordering::SeqCst);
}
};
diff --git a/tests/cancel.rs b/tests/cancel.rs
index 4f77ae5..0fe7c72 100644
--- a/tests/cancel.rs
+++ b/tests/cancel.rs
@@ -81,7 +81,7 @@ macro_rules! schedule {
let guard = Guard(Box::new(0));
move |runnable: Runnable| {
- &guard;
+ let _ = &guard;
runnable.schedule();
$sched.fetch_add(1, Ordering::SeqCst);
}
diff --git a/tests/join.rs b/tests/join.rs
index 17312a4..2ac7b8d 100644
--- a/tests/join.rs
+++ b/tests/join.rs
@@ -82,7 +82,7 @@ macro_rules! schedule {
let guard = Guard(Box::new(0));
move |runnable: Runnable| {
- &guard;
+ let _ = &guard;
runnable.schedule();
$sched.fetch_add(1, Ordering::SeqCst);
}
diff --git a/tests/panic.rs b/tests/panic.rs
index f38fb3e..09ffb28 100644
--- a/tests/panic.rs
+++ b/tests/panic.rs
@@ -69,7 +69,7 @@ macro_rules! schedule {
let guard = Guard(Box::new(0));
move |_runnable: Runnable| {
- &guard;
+ let _ = &guard;
$sched.fetch_add(1, Ordering::SeqCst);
}
};
diff --git a/tests/ready.rs b/tests/ready.rs
index ebfdc63..e345565 100644
--- a/tests/ready.rs
+++ b/tests/ready.rs
@@ -81,7 +81,7 @@ macro_rules! schedule {
let guard = Guard(Box::new(0));
move |_runnable: Runnable| {
- &guard;
+ let _ = &guard;
$sched.fetch_add(1, Ordering::SeqCst);
}
};
diff --git a/tests/waker_panic.rs b/tests/waker_panic.rs
index 68b0a81..7a7792e 100644
--- a/tests/waker_panic.rs
+++ b/tests/waker_panic.rs
@@ -86,7 +86,7 @@ macro_rules! schedule {
let guard = Guard(Box::new(0));
let sched = move |runnable: Runnable| {
- &guard;
+ let _ = &guard;
$sched.fetch_add(1, Ordering::SeqCst);
s.send(runnable).unwrap();
};
@@ -238,10 +238,15 @@ fn wake_and_cancel_during_run() {
.run();
}
-#[test]
+#[flaky_test::flaky_test]
fn cancel_and_wake_during_run() {
future!(f, get_waker, POLL, DROP_F);
schedule!(s, chan, SCHEDULE, DROP_S);
+ POLL.store(0, Ordering::SeqCst);
+ DROP_F.store(0, Ordering::SeqCst);
+ SCHEDULE.store(0, Ordering::SeqCst);
+ DROP_S.store(0, Ordering::SeqCst);
+
let (runnable, task) = async_task::spawn(f, s);
runnable.run();
diff --git a/tests/waker_pending.rs b/tests/waker_pending.rs
index e30af33..9c95cba 100644
--- a/tests/waker_pending.rs
+++ b/tests/waker_pending.rs
@@ -77,7 +77,7 @@ macro_rules! schedule {
let guard = Guard(Box::new(0));
let sched = move |runnable: Runnable| {
- &guard;
+ let _ = &guard;
$sched.fetch_add(1, Ordering::SeqCst);
s.send(runnable).unwrap();
};
diff --git a/tests/waker_ready.rs b/tests/waker_ready.rs
index d46fd6f..10d38cb 100644
--- a/tests/waker_ready.rs
+++ b/tests/waker_ready.rs
@@ -83,7 +83,7 @@ macro_rules! schedule {
let guard = Guard(Box::new(0));
let sched = move |runnable: Runnable| {
- &guard;
+ let _ = &guard;
$sched.fetch_add(1, Ordering::SeqCst);
s.send(runnable).unwrap();
};