bugfix: Ensure that ex.run() produces a Send future

This commit makes sure that the run() and tick() functions produce
futures that are Send and Sync, to prevent a regression introduced in
PR #37. Tests are also added to prevent this regression in the future.

Signed-off-by: John Nunley <dev@notgull.net>
This commit is contained in:
John Nunley 2023-08-20 17:08:35 -07:00 committed by GitHub
parent e19573367b
commit a5ff8df7d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 37 additions and 3 deletions

View File

@ -269,7 +269,7 @@ impl<'a> Executor<'a> {
// Try to push into the local queue.
LocalQueue::with(|local_queue| {
// Make sure that we don't accidentally push to an executor that isn't ours.
if !std::ptr::eq(local_queue.state, &*state) {
if local_queue.state != &*state as *const State as usize {
return;
}
@ -858,7 +858,7 @@ struct LocalQueue {
/// The pointer to the state of the executor.
///
/// Used to make sure we don't push runnables to the wrong executor.
state: *const State,
state: usize,
/// The concurrent queue.
queue: Arc<ConcurrentQueue<Runnable>>,
@ -889,7 +889,7 @@ impl LocalQueue {
let mut old = with_waker(|waker| {
LOCAL_QUEUE.with(move |slot| {
slot.borrow_mut().replace(LocalQueue {
state: state as *const State,
state: state as *const State as usize,
queue: queue.clone(),
waker: waker.clone(),
})
@ -1052,3 +1052,37 @@ fn with_waker<F: FnOnce(&Waker) -> R, R>(f: F) -> impl Future<Output = R> {
Poll::Ready(f(cx.waker()))
})
}
fn _ensure_send_and_sync() {
use futures_lite::future::pending;
fn is_send<T: Send>(_: T) {}
fn is_sync<T: Sync>(_: T) {}
is_send::<Executor<'_>>(Executor::new());
is_sync::<Executor<'_>>(Executor::new());
let ex = Executor::new();
is_send(ex.run(pending::<()>()));
is_sync(ex.run(pending::<()>()));
is_send(ex.tick());
is_sync(ex.tick());
/// ```compile_fail
/// use async_executor::LocalExecutor;
/// use futures_lite::future::pending;
///
/// fn is_send<T: Send>(_: T) {}
/// fn is_sync<T: Sync>(_: T) {}
///
/// is_send::<LocalExecutor<'_>>(LocalExecutor::new());
/// is_sync::<LocalExecutor<'_>>(LocalExecutor::new());
///
/// let ex = LocalExecutor::new();
/// is_send(ex.run(pending::<()>()));
/// is_sync(ex.run(pending::<()>()));
/// is_send(ex.tick());
/// is_sync(ex.tick());
/// ```
fn _negative_test() {}
}