rt: move budget state to context thread-local (#5157)

This patch consolidates the budget thread-local state with the
`runtime::context` thread local. This reduces the number of thread-local
variables used by Tokio by one.
This commit is contained in:
Carl Lerche
2022-11-02 12:24:12 -07:00
committed by GitHub
parent ca8e176ce9
commit d8ee205530
3 changed files with 28 additions and 14 deletions
+17
View File
@@ -1,3 +1,8 @@
use crate::runtime::coop;
use std::cell::Cell;
#[cfg(any(feature = "rt", feature = "macros"))]
use crate::util::rand::{FastRand, RngSeed}; use crate::util::rand::{FastRand, RngSeed};
cfg_rt! { cfg_rt! {
@@ -9,7 +14,12 @@ struct Context {
/// Handle to the runtime scheduler running on the current thread. /// Handle to the runtime scheduler running on the current thread.
#[cfg(feature = "rt")] #[cfg(feature = "rt")]
scheduler: RefCell<Option<scheduler::Handle>>, scheduler: RefCell<Option<scheduler::Handle>>,
#[cfg(any(feature = "rt", feature = "macros"))]
rng: FastRand, rng: FastRand,
/// Tracks the amount of "work" a task may still do before yielding back to
/// the sheduler
budget: Cell<coop::Budget>,
} }
tokio_thread_local! { tokio_thread_local! {
@@ -17,7 +27,10 @@ tokio_thread_local! {
Context { Context {
#[cfg(feature = "rt")] #[cfg(feature = "rt")]
scheduler: RefCell::new(None), scheduler: RefCell::new(None),
#[cfg(any(feature = "rt", feature = "macros"))]
rng: FastRand::new(RngSeed::new()), rng: FastRand::new(RngSeed::new()),
budget: Cell::new(coop::Budget::unconstrained()),
} }
} }
} }
@@ -27,6 +40,10 @@ pub(crate) fn thread_rng_n(n: u32) -> u32 {
CONTEXT.with(|ctx| ctx.rng.fastrand_n(n)) CONTEXT.with(|ctx| ctx.rng.fastrand_n(n))
} }
pub(super) fn budget<R>(f: impl FnOnce(&Cell<coop::Budget>) -> R) -> R {
CONTEXT.with(|ctx| f(&ctx.budget))
}
cfg_rt! { cfg_rt! {
use crate::runtime::TryCurrentError; use crate::runtime::TryCurrentError;
+11 -13
View File
@@ -29,11 +29,9 @@
// other futures. By doing this, you avoid double-counting each iteration of // other futures. By doing this, you avoid double-counting each iteration of
// the outer future against the cooperating budget. // the outer future against the cooperating budget.
use std::cell::Cell; use crate::runtime::context;
tokio_thread_local! { use std::cell::Cell;
static CURRENT: Cell<Budget> = const { Cell::new(Budget::unconstrained()) };
}
/// Opaque type tracking the amount of "work" a task may still do before /// Opaque type tracking the amount of "work" a task may still do before
/// yielding back to the scheduler. /// yielding back to the scheduler.
@@ -56,7 +54,7 @@ impl Budget {
} }
/// Returns an unconstrained budget. Operations will not be limited. /// Returns an unconstrained budget. Operations will not be limited.
const fn unconstrained() -> Budget { pub(super) const fn unconstrained() -> Budget {
Budget(None) Budget(None)
} }
@@ -92,7 +90,7 @@ fn with_budget<R>(budget: Budget, f: impl FnOnce() -> R) -> R {
} }
} }
CURRENT.with(move |cell| { context::budget(|cell| {
let prev = cell.get(); let prev = cell.get();
cell.set(budget); cell.set(budget);
@@ -105,13 +103,13 @@ fn with_budget<R>(budget: Budget, f: impl FnOnce() -> R) -> R {
#[inline(always)] #[inline(always)]
pub(crate) fn has_budget_remaining() -> bool { pub(crate) fn has_budget_remaining() -> bool {
CURRENT.with(|cell| cell.get().has_remaining()) context::budget(|cell| cell.get().has_remaining())
} }
cfg_rt_multi_thread! { cfg_rt_multi_thread! {
/// Sets the current task's budget. /// Sets the current task's budget.
pub(crate) fn set(budget: Budget) { pub(crate) fn set(budget: Budget) {
CURRENT.with(|cell| cell.set(budget)) context::budget(|cell| cell.set(budget))
} }
} }
@@ -120,7 +118,7 @@ cfg_rt! {
/// ///
/// Returns the remaining budget /// Returns the remaining budget
pub(crate) fn stop() -> Budget { pub(crate) fn stop() -> Budget {
CURRENT.with(|cell| { context::budget(|cell| {
let prev = cell.get(); let prev = cell.get();
cell.set(Budget::unconstrained()); cell.set(Budget::unconstrained());
prev prev
@@ -146,7 +144,7 @@ cfg_coop! {
// They are both represented as the remembered budget being unconstrained. // They are both represented as the remembered budget being unconstrained.
let budget = self.0.get(); let budget = self.0.get();
if !budget.is_unconstrained() { if !budget.is_unconstrained() {
CURRENT.with(|cell| { context::budget(|cell| {
cell.set(budget); cell.set(budget);
}); });
} }
@@ -162,12 +160,12 @@ cfg_coop! {
/// that the budget empties appropriately. /// that the budget empties appropriately.
/// ///
/// Note that `RestoreOnPending` restores the budget **as it was before `poll_proceed`**. /// Note that `RestoreOnPending` restores the budget **as it was before `poll_proceed`**.
/// Therefore, if the budget is _further_ adjusted between when `poll_proceed` returns and /// Therefore, if the budget is _fCURRENT.withurther_ adjusted between when `poll_proceed` returns and
/// `RestRestoreOnPending` is dropped, those adjustments are erased unless the caller indicates /// `RestRestoreOnPending` is dropped, those adjustments are erased unless the caller indicates
/// that progress was made. /// that progress was made.
#[inline] #[inline]
pub(crate) fn poll_proceed(cx: &mut Context<'_>) -> Poll<RestoreOnPending> { pub(crate) fn poll_proceed(cx: &mut Context<'_>) -> Poll<RestoreOnPending> {
CURRENT.with(|cell| { context::budget(|cell| {
let mut budget = cell.get(); let mut budget = cell.get();
if budget.decrement() { if budget.decrement() {
@@ -211,7 +209,7 @@ mod test {
use wasm_bindgen_test::wasm_bindgen_test as test; use wasm_bindgen_test::wasm_bindgen_test as test;
fn get() -> Budget { fn get() -> Budget {
CURRENT.with(|cell| cell.get()) context::budget(|cell| cell.get())
} }
#[test] #[test]
-1
View File
@@ -177,7 +177,6 @@
#[macro_use] #[macro_use]
mod tests; mod tests;
#[cfg(any(feature = "rt", feature = "macros"))]
pub(crate) mod context; pub(crate) mod context;
pub(crate) mod coop; pub(crate) mod coop;