Actix - C callbacks

Hello.
I have a function for register Closure (C callback) - set_write_callback().
I would like send a message in callback body.

pub fn set_write_callback<T, Closure>(&mut self, callback: Closure) 
-> Result<(), String> 
where     
Closure: FnMut(u32, T) -> Result<(), String>,     
Closure: 'static + Sized,     
Closure: panic::RefUnwindSafe,     
T: std::fmt::Display + Default,
//...
var.set_write_callback::<bool, _>(move |p_arg, state  |{
    let value: u8;
    if state { value = 1; } else { value = 0; }

    address.do_send(PushData::new("Test".to_string(), value));
    return Ok(());
}).expect("Error");

Error:
may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary

error[E0277]: the type `std::cell::UnsafeCell<actix::address::channel::ReceiverTask>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
   --> src/main.rs:215:25
    |
215 |                       var.set_write_callback::<bool, _>(
    |                           ^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell<actix::address::channel::ReceiverTask>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
216 | /                         move |p_arg, state  |{
...   |
226 | |                             return Ok(());
227 | |                         }).expect("Error");
    | |_________________________- within this `[closure@src/main.rs:216:25: 227:26 iec_var_name:std::string::String, address:actix::address::Addr<datahub::DataHub>]`
    |
    = help: within `[closure@src/main.rs:216:25: 227:26 iec_var_name:std::string::String, address:actix::address::Addr<datahub::DataHub>]`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<actix::address::channel::ReceiverTask>`
    = note: required because it appears within the type `lock_api::mutex::Mutex<parking_lot::raw_mutex::RawMutex, actix::address::channel::ReceiverTask>`
    = note: required because it appears within the type `actix::address::channel::Inner<datahub::DataHub>`
    = note: required because it appears within the type `alloc::sync::ArcInner<actix::address::channel::Inner<datahub::DataHub>>`
    = note: required because it appears within the type `std::marker::PhantomData<alloc::sync::ArcInner<actix::address::channel::Inner<datahub::DataHub>>>`
    = note: required because it appears within the type `std::sync::Arc<actix::address::channel::Inner<datahub::DataHub>>`
    = note: required because it appears within the type `actix::address::channel::AddressSender<datahub::DataHub>`
    = note: required because it appears within the type `actix::address::Addr<datahub::DataHub>`
    = note: required because it appears within the type `[closure@src/main.rs:216:25: 227:26 iec_var_name:std::string::String, address:actix::address::Addr<datahub::DataHub>]`

How to fix it?

Rust was told to guarantee that the closure is safe to use after a panic!() ( Closure: panic::RefUnwindSafe), which means everything that this closure touches must be unwind safe, but Actix's ReceiverTask was not declared to survive panics.

You're using parking_lot's Mutex which doesn't add that guarantee. If you used std's Mutex it would (std "poisons" mutexes on panic).

If you're sure it's not a problem and want to force this through, you can wrap ReceiverTask in your own struct (newtype) and impl RefUnwindSafe for your newtype.

I do not know how to do this. I am asking for an example.

Try to read @kornel's response for a better solution, but the "quick and dirty" way to fix it would be:

+ let address = ::std::panic::AssertUnwindSafe(address);
  var.set_write_callback::<bool, _>(move |p_arg, state  |{
      let value: u8;
      if state { value = 1; } else { value = 0; }

      address.do_send(PushData::new("Test".to_string(), value));
      return Ok(());
  }).expect("Error");
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.