diff options
author | Carl Lerche <me@carllerche.com> | 2019-11-29 10:23:22 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-11-29 10:23:22 -0800 |
commit | a2cfc877a7f45eb0e1ae8d2775e22ee91da725ec (patch) | |
tree | c3f6b092cd23975205c94933e396e9b309bbf500 /tokio/src/runtime/basic_scheduler.rs | |
parent | ec7f2ae30629e5ec164d2a65de9341cf049a2a0b (diff) |
rt: fix `basic_scheduler` notification bug (#1861)
The "global executor" thread-local is to track where to spawn new tasks,
**not** which scheduler is active on the current thread. This fixes a
bug with scheduling tasks on the basic_scheduler by tracking the
currently active basic_scheduler with a dedicated thread-local variable.
Fixes: #1851
Diffstat (limited to 'tokio/src/runtime/basic_scheduler.rs')
-rw-r--r-- | tokio/src/runtime/basic_scheduler.rs | 34 |
1 files changed, 31 insertions, 3 deletions
diff --git a/tokio/src/runtime/basic_scheduler.rs b/tokio/src/runtime/basic_scheduler.rs index 48c8ad9e..c674b961 100644 --- a/tokio/src/runtime/basic_scheduler.rs +++ b/tokio/src/runtime/basic_scheduler.rs @@ -1,11 +1,12 @@ use crate::park::{Park, Unpark}; use crate::task::{self, JoinHandle, Schedule, ScheduleSendOnly, Task}; -use std::cell::UnsafeCell; +use std::cell::{Cell, UnsafeCell}; use std::collections::VecDeque; use std::fmt; use std::future::Future; use std::mem::ManuallyDrop; +use std::ptr; use std::sync::{Arc, Mutex}; use std::task::{RawWaker, RawWakerVTable, Waker}; use std::time::Duration; @@ -87,6 +88,10 @@ const MAX_TASKS_PER_TICK: usize = 61; /// How often to check the remote queue first const CHECK_REMOTE_INTERVAL: u8 = 13; +thread_local! { + static ACTIVE: Cell<*const SchedulerPriv> = Cell::new(ptr::null()) +} + impl<P> BasicScheduler<P> where P: Park, @@ -138,6 +143,27 @@ where let local = &mut self.local; let scheduler = &*self.scheduler; + struct Guard { + old: *const SchedulerPriv, + } + + impl Drop for Guard { + fn drop(&mut self) { + ACTIVE.with(|cell| cell.set(self.old)); + } + } + + // Track the current scheduler + let _guard = ACTIVE.with(|cell| { + let guard = Guard { + old: cell.get(), + }; + + cell.set(scheduler as *const SchedulerPriv); + + guard + }); + runtime::global::with_basic_scheduler(scheduler, || { let mut _enter = runtime::enter(); @@ -283,9 +309,11 @@ impl Schedule for SchedulerPriv { } fn schedule(&self, task: Task<Self>) { - use crate::runtime::global; + let is_current = ACTIVE.with(|cell| { + cell.get() == self as *const SchedulerPriv + }); - if global::basic_scheduler_is_current(self) { + if is_current { unsafe { self.schedule_local(task) }; } else { let mut lock = self.remote_queue.lock().unwrap(); |