Repository: tokio-rs/tokio (Rust)

Issue:
`tokio::sync::Notify` is not Unwind Safe
**Version**
1.21.2

**Platform**
Rust playground and Linux, Ubuntu 20.04.

**Description**
I was trying to `catch_unwind` in a project depending on Tokio's `tokio::sync::Notify` primitive, and ran into a compile error because `Notify` is not unwind safe.

I'm not sure if this is technically a bug or a feature request.

I tried this code:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c1409cc70ceea71c7d28c41f7232e19c

```rust
#[tokio::main]
async fn main() {
    let notify = tokio::sync::Notify::new();
    
    std::panic::catch_unwind(|| {
        notify.notify_one();
    });
}
```

I expected to see this happen: No compile error

Instead, this happened:

```
Compiling playground v0.0.1 (/playground)
error[[E0277]](https://doc.rust-lang.org/stable/error-index.html#E0277): the type `UnsafeCell<AtomicUsize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
 --> src/main.rs:5:5
  |
5 |     std::panic::catch_unwind(|| {
  |     ^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<AtomicUsize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
  |
  = help: within `Notify`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<AtomicUsize>`
  = note: required because it appears within the type `tokio::loom::std::atomic_usize::AtomicUsize`
  = note: required because it appears within the type `Notify`
  = note: required because of the requirements on the impl of `UnwindSafe` for `&Notify`
note: required because it's used within this closure
 --> src/main.rs:5:30
  |
5 |     std::panic::catch_unwind(|| {
  |                              ^^
note: required by a bound in `catch_unwind`

error[[E0277]](https://doc.rust-lang.org/stable/error-index.html#E0277): the type `UnsafeCell<tokio::util::linked_list::LinkedList<tokio::sync::notify::Waiter, tokio::sync::notify::Waiter>>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
 --> src/main.rs:5:5
  |
5 |     std::panic::catch_unwind(|| {
  |     ^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<tokio::util::linked_list::LinkedList<tokio::sync::notify::Waiter, tokio::sync::notify::Waiter>>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
  |
  = help: within `Notify`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<tokio::util::linked_list::LinkedList<tokio::sync::notify::Waiter, tokio::sync::notify::Waiter>>`
  = note: required because it appears within the type `lock_api::mutex::Mutex<parking_lot::raw_mutex::RawMutex, tokio::util::linked_list::LinkedList<tokio::sync::notify::Waiter, tokio::sync::notify::Waiter>>`
  = note: required because it appears within the type `tokio::loom::std::parking_lot::Mutex<tokio::util::linked_list::LinkedList<tokio::sync::notify::Waiter, tokio::sync::notify::Waiter>>`
  = note: required because it appears within the type `Notify`
  = note: required because of the requirements on the impl of `UnwindSafe` for `&Notify`
note: required because it's used within this closure
 --> src/main.rs:5:30
  |
5 |     std::panic::catch_unwind(|| {
  |                              ^^
note: required by a bound in `catch_unwind`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` due to 2 previous errors
```


Discussion:
Sure, we can do that.



Patch:
diff --git a/tokio/src/sync/notify.rs b/tokio/src/sync/notify.rs
index 83bd6823694..efe16f9f8ef 100644
--- a/tokio/src/sync/notify.rs
+++ b/tokio/src/sync/notify.rs
@@ -13,6 +13,7 @@ use crate::util::WakeList;
 use std::cell::UnsafeCell;
 use std::future::Future;
 use std::marker::PhantomPinned;
+use std::panic::{RefUnwindSafe, UnwindSafe};
 use std::pin::Pin;
 use std::ptr::NonNull;
 use std::sync::atomic::Ordering::SeqCst;
@@ -566,6 +567,9 @@ impl Default for Notify {
     }
 }
 
+impl UnwindSafe for Notify {}
+impl RefUnwindSafe for Notify {}
+
 fn notify_locked(waiters: &mut WaitList, state: &AtomicUsize, curr: usize) -> Option<Waker> {
     loop {
         match get_state(curr) {


Test patch:
diff --git a/tokio/tests/unwindsafe.rs b/tokio/tests/unwindsafe.rs
index 98cf5b1b044..3e63820864d 100644
--- a/tokio/tests/unwindsafe.rs
+++ b/tokio/tests/unwindsafe.rs
@@ -3,6 +3,11 @@
 
 use std::panic::{RefUnwindSafe, UnwindSafe};
 
+#[test]
+fn notify_is_unwind_safe() {
+    is_unwind_safe::<tokio::sync::Notify>();
+}
+
 #[test]
 fn join_handle_is_unwind_safe() {
     is_unwind_safe::<tokio::task::JoinHandle<()>>();