2

I'm trying to build a shared library module to be loaded by Kamailio using rust-bindgen. The module interface requires a symbol exports pointing to a C struct defined in Kamailio.

This struct contains some function pointers and other pointer fields (declared as const *T) and thus cannot implement Sync. How do I export such a symbol in safe or unsafe Rust?

Do I need to write a wrapper C object for my Rust shared library module just to export this symbol?

I am using stable Rust 2018 Edition and latest rust-bindgen.

This is the declaration of the struct type for the module exports symbol. Generated by bindgen and adapted by me.

#[doc = " kamailio/openser module exports version"]
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct kam_module_exports {
    #[doc = "< null terminated module name"]
    pub name: *const ::std::os::raw::c_char,
    #[doc = "< flags for dlopen"]
    pub dlflags: ::std::os::raw::c_uint,
    #[doc = "< null terminated array of the exported"]
    #[doc = "commands"]
    pub cmds: *const kam_cmd_export_t,
    #[doc = "< null terminated array of the exported"]
    #[doc = "module parameters"]
    pub params: *const param_export_t,
    #[doc = "< null terminated array of the exported"]
    #[doc = "module statistics"]
    pub stats: *const stat_export_t,
    #[doc = "< null terminated array of the exported"]
    #[doc = "NN functions"]
    pub nn_cmds: *const nn_export_t,
    #[doc = "< null terminated array of the exported"]
    #[doc = "module items (pseudo-variables)"]
    pub items: *const pv_export_t,
    #[doc = "< null terminated array of the"]
    #[doc = "additional processes required by the"]
    #[doc = "module"]
    pub procs: *const proc_export_t,
    #[doc = "< Initialization function"]
    pub init_f: init_function,
    #[doc = "< function used for responses,"]
    #[doc = "returns yes or no; can be null"]
    pub response_f: response_function,
    #[doc = "< function called when the module should"]
    #[doc = "be \"destroyed\", e.g: on ser exit;"]
    #[doc = "can be null"]
    pub destroy_f: destroy_function,
    #[doc = "< function called by all processes"]
    #[doc = "after the fork"]
    pub init_child_f: child_init_function,
}

The exports symbol is declared like so:

#[no_mangle]
pub static exports: *const ::kamailio_mod::kam_module_exports =
            &::kamailio_mod::kam_module_exports {
                name: &name[0],
                dlflags: 0,
                cmds: &cmd_exports[0],
                params: ::std::ptr::null_mut(),
                stats: ::std::ptr::null_mut(),
                nn_cmds: ::std::ptr::null_mut(),
                items: ::std::ptr::null_mut(),
                procs: ::std::ptr::null_mut(),
                init_f: None,
                response_f: None,
                destroy_f: None,
                init_child_f: None,
            };

error[E0277]: *const kamailio_mod::kam_module_exports cannot be shared between threads safely

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Emil
  • 21
  • 2
  • I believe your question is answered by the answers of [How can I guarantee that a type that doesn't implement Sync can actually be safely shared between threads?](https://stackoverflow.com/q/36649865/155423). If you disagree, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster May 19 '19 at 14:31
  • Thanks for the reference. You are right, I can declare a newtype struct for the `exports` symbol (i.e `pub struct ModuleExports(pub *const kam_module_exports)`) and unsafe implement `Sync` for it. This makes the compiler pass the code. – Emil May 19 '19 at 21:28

0 Answers0