Skip to content

Commit e951d55

Browse files
authored
rt: refactor current-thread scheduler (take 2) (#4395)
Re-applies #4377 and fixes the bug resulting in Hyper's double panic. Revert: #4394 Original PR: This PR does some refactoring to the current-thread scheduler bringing it closer to the structure of the multi-threaded scheduler. More specifically, the core scheduler data is stored in a Core struct and that struct is passed around as a "token" indicating permission to do work. The Core structure is also stored in the thread-local context. This refactor is intended to support #4373, making it easier to track counters in more locations in the current-thread scheduler. I tried to keep commits small, but the "set Core in thread-local context" is both the biggest commit and the key one.
1 parent 1d698b5 commit e951d55

File tree

8 files changed

+275
-215
lines changed

8 files changed

+275
-215
lines changed

tokio/src/runtime/basic_scheduler.rs

Lines changed: 224 additions & 196 deletions
Large diffs are not rendered by default.

tokio/src/runtime/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ cfg_rt! {
283283
#[derive(Debug)]
284284
enum Kind {
285285
/// Execute all tasks on the current-thread.
286-
CurrentThread(BasicScheduler<driver::Driver>),
286+
CurrentThread(BasicScheduler),
287287

288288
/// Execute tasks across multiple threads.
289289
#[cfg(feature = "rt-multi-thread")]

tokio/src/runtime/tests/loom_basic_scheduler.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,22 @@ fn assert_at_most_num_polls(rt: Arc<Runtime>, at_most_polls: usize) {
3434
#[test]
3535
fn block_on_num_polls() {
3636
loom::model(|| {
37-
// we expect at most 3 number of polls because there are
38-
// three points at which we poll the future. At any of these
39-
// points it can be ready:
37+
// we expect at most 4 number of polls because there are three points at
38+
// which we poll the future and an opportunity for a false-positive.. At
39+
// any of these points it can be ready:
4040
//
41-
// - when we fail to steal the parker and we block on a
42-
// notification that it is available.
41+
// - when we fail to steal the parker and we block on a notification
42+
// that it is available.
4343
//
4444
// - when we steal the parker and we schedule the future
4545
//
46-
// - when the future is woken up and we have ran the max
47-
// number of tasks for the current tick or there are no
48-
// more tasks to run.
46+
// - when the future is woken up and we have ran the max number of tasks
47+
// for the current tick or there are no more tasks to run.
4948
//
50-
let at_most = 3;
49+
// - a thread is notified that the parker is available but a third
50+
// thread acquires it before the notified thread can.
51+
//
52+
let at_most = 4;
5153

5254
let rt1 = Arc::new(Builder::new_current_thread().build().unwrap());
5355
let rt2 = rt1.clone();

tokio/src/runtime/thread_pool/mod.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
//! Threadpool
22
3-
mod atomic_cell;
4-
use atomic_cell::AtomicCell;
5-
63
mod idle;
74
use self::idle::Idle;
85

tokio/src/runtime/thread_pool/worker.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,9 @@ use crate::runtime::enter::EnterContext;
6666
use crate::runtime::park::{Parker, Unparker};
6767
use crate::runtime::stats::{RuntimeStats, WorkerStatsBatcher};
6868
use crate::runtime::task::{Inject, JoinHandle, OwnedTasks};
69-
use crate::runtime::thread_pool::{AtomicCell, Idle};
69+
use crate::runtime::thread_pool::Idle;
7070
use crate::runtime::{queue, task, Callback};
71+
use crate::util::atomic_cell::AtomicCell;
7172
use crate::util::FastRand;
7273

7374
use std::cell::RefCell;

tokio/src/runtime/thread_pool/atomic_cell.rs renamed to tokio/src/util/atomic_cell.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,30 @@ use crate::loom::sync::atomic::AtomicPtr;
33
use std::ptr;
44
use std::sync::atomic::Ordering::AcqRel;
55

6-
pub(super) struct AtomicCell<T> {
6+
pub(crate) struct AtomicCell<T> {
77
data: AtomicPtr<T>,
88
}
99

1010
unsafe impl<T: Send> Send for AtomicCell<T> {}
1111
unsafe impl<T: Send> Sync for AtomicCell<T> {}
1212

1313
impl<T> AtomicCell<T> {
14-
pub(super) fn new(data: Option<Box<T>>) -> AtomicCell<T> {
14+
pub(crate) fn new(data: Option<Box<T>>) -> AtomicCell<T> {
1515
AtomicCell {
1616
data: AtomicPtr::new(to_raw(data)),
1717
}
1818
}
1919

20-
pub(super) fn swap(&self, val: Option<Box<T>>) -> Option<Box<T>> {
20+
pub(crate) fn swap(&self, val: Option<Box<T>>) -> Option<Box<T>> {
2121
let old = self.data.swap(to_raw(val), AcqRel);
2222
from_raw(old)
2323
}
2424

25-
pub(super) fn set(&self, val: Box<T>) {
25+
pub(crate) fn set(&self, val: Box<T>) {
2626
let _ = self.swap(Some(val));
2727
}
2828

29-
pub(super) fn take(&self) -> Option<Box<T>> {
29+
pub(crate) fn take(&self) -> Option<Box<T>> {
3030
self.swap(None)
3131
}
3232
}

tokio/src/util/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ cfg_io_driver! {
33
pub(crate) mod slab;
44
}
55

6+
#[cfg(feature = "rt")]
7+
pub(crate) mod atomic_cell;
8+
69
#[cfg(any(
710
// io driver uses `WakeList` directly
811
feature = "net",

tokio/tests/rt_basic.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,35 @@ fn drop_tasks_in_context() {
168168
assert!(SUCCESS.load(Ordering::SeqCst));
169169
}
170170

171+
#[test]
172+
#[should_panic(expected = "boom")]
173+
fn wake_in_drop_after_panic() {
174+
let (tx, rx) = oneshot::channel::<()>();
175+
176+
struct WakeOnDrop(Option<oneshot::Sender<()>>);
177+
178+
impl Drop for WakeOnDrop {
179+
fn drop(&mut self) {
180+
self.0.take().unwrap().send(()).unwrap();
181+
}
182+
}
183+
184+
let rt = rt();
185+
186+
rt.spawn(async move {
187+
let _wake_on_drop = WakeOnDrop(Some(tx));
188+
// wait forever
189+
futures::future::pending::<()>().await;
190+
});
191+
192+
let _join = rt.spawn(async move { rx.await });
193+
194+
rt.block_on(async {
195+
tokio::task::yield_now().await;
196+
panic!("boom");
197+
});
198+
}
199+
171200
#[test]
172201
#[should_panic(
173202
expected = "A Tokio 1.x context was found, but timers are disabled. Call `enable_time` on the runtime builder to enable timers."

0 commit comments

Comments
 (0)