Repository: tokio-rs/tokio
File: tokio/src/runtime/context.rs (Rust)

Code before:
    /// Tries to enter a runtime context, returns `None` if already in a runtime
    /// context.
    fn try_enter_runtime(allow_block_in_place: bool) -> Option<EnterRuntimeGuard> {
        CONTEXT.with(|c| {
            if c.runtime.get().is_entered() {
                None
            } else {
                c.runtime.set(EnterRuntime::Entered { allow_block_in_place });
                Some(EnterRuntimeGuard {
                    blocking: BlockingRegionGuard::new(),
                })
            }
        })
    }

    pub(crate) fn try_enter_blocking_region() -> Option<BlockingRegionGuard> {
        CONTEXT.try_with(|c| {
            if c.runtime.get().is_entered() {
                None
            } else {
                Some(BlockingRegionGuard::new())
            }
            // If accessing the thread-local fails, the thread is terminating
            // and thread-locals are being destroyed. Because we don't know if
            // we are currently in a runtime or not, we default to being
            // permissive.
        }).unwrap_or(Some(BlockingRegionGuard::new()))
    }

    /// Disallows blocking in the current runtime context until the guard is dropped.
    pub(crate) fn disallow_block_in_place() -> DisallowBlockInPlaceGuard {
        let reset = CONTEXT.with(|c| {
            if let EnterRuntime::Entered {
                allow_block_in_place: true,
            } = c.runtime.get()
            {
                c.runtime.set(EnterRuntime::Entered {
                    allow_block_in_place: false,
                });
                true
            } else {
                false
            }
        });

        DisallowBlockInPlaceGuard(reset)
    }

    impl Context {
        fn set_current(&self, handle: &scheduler::Handle) -> SetCurrentGuard {
            let rng_seed = handle.seed_generator().next_seed();

Review comment (bug):
The test that failed tested storing a runtime in a thread-local. I think the test just happened to pass before due to the order in which thread-local variables were destroyed. This is a behavior change, but I think it is necessary, otherwise shutting down a runtime from a thread-local can double panic and abort the process.

Code after:
    /// Tries to enter a runtime context, returns `None` if already in a runtime
    /// context.
    fn try_enter_runtime(allow_block_in_place: bool) -> Option<EnterRuntimeGuard> {
        CONTEXT.with(|c| {
            if c.runtime.get().is_entered() {
                None
            } else {
                c.runtime.set(EnterRuntime::Entered { allow_block_in_place });
                Some(EnterRuntimeGuard {
                    blocking: BlockingRegionGuard::new(),
                })
            }
        })
    }

    pub(crate) fn try_enter_blocking_region() -> Option<BlockingRegionGuard> {
        CONTEXT.try_with(|c| {
            if c.runtime.get().is_entered() {
                None
            } else {
                Some(BlockingRegionGuard::new())
            }
            // If accessing the thread-local fails, the thread is terminating
            // and thread-locals are being destroyed. Because we don't know if
            // we are currently in a runtime or not, we default to being
            // permissive.
        }).unwrap_or_else(|_| Some(BlockingRegionGuard::new()))
    }

    /// Disallows blocking in the current runtime context until the guard is dropped.
    pub(crate) fn disallow_block_in_place() -> DisallowBlockInPlaceGuard {
        let reset = CONTEXT.with(|c| {
            if let EnterRuntime::Entered {
                allow_block_in_place: true,
            } = c.runtime.get()
            {
                c.runtime.set(EnterRuntime::Entered {
                    allow_block_in_place: false,
                });
                true
            } else {
                false
            }
        });

        DisallowBlockInPlaceGuard(reset)
    }

    impl Context {
        fn set_current(&self, handle: &scheduler::Handle) -> SetCurrentGuard {
            let rng_seed = handle.seed_generator().next_seed();