Why we immediately replace back the new value with the old one?

The source code I am referring to is located here: https://github.com/tokio-rs/tokio/blob/master/tokio/src/runtime/context.rs

    thread_local! {
        static CONTEXT: RefCell<Option<Handle>> = RefCell::new(None)
    }
    /// Set this [`Handle`] as the current active [`Handle`].
    ///
    /// [`Handle`]: Handle
    pub(crate) fn enter<F, R>(new: Handle, f: F) -> R
    where 
        F: FnOnce() -> R,
    {
        struct DropGuard(Option<Handle>);

        impl Drop for DropGuard {
            fn drop(&mut self) {
                CONTEXT.with(|ctx| {
                    *ctx.borrow_mut() = self.0.take();
                })
            }
        }

        let _guard = CONTEXT.with(|ctx| {
            let old = ctx.borrow_mut().replace(new);
            DropGuard(old)
        });

        f()
    }   // <------------ fn drop()  method gets called here? 

I am not able to understand why we immediately replace back the wrapped Option with the value old, as soon as we return from this function.

I might be lacking understanding of how the drop method works, but it seems that it gets invoked when '_guard' variable goes out of scope. It means that the handle is only active during the execution of function 'f'.

I apologize if this answer to this question is straightforward.

Doing it this way will cause the handle to be restored to the old value by the drop impl of DropGuard even when there is a panic.

3 Likes

Thanks. Can you please explain the part about panic or maybe give an example?

If it was written like

pub(crate) fn enter<F, R>(new: Handle, f: F) -> R
where
    F: FnOnce() -> R,
{
    let old = CONTEXT.with(|ctx| {
        ctx.borrow_mut().replace(new)
    });

    let val = f();
    
    CONTEXT.with(|ctx| {
        *ctx.borrow_mut() = old
    });
    
    val
}

Then if f() panics, CONTEXT.with(|ctx| { *ctx.borrow_mut() = old }); will never be executed. With the code written as is the drop impl of DropGuard will run when either returning normally or when unwinding the stack.

2 Likes

Thanks it is clear now.