Как сделать контейнер stati c для ссылки на изменяемый экземпляр из обратного вызова, переданного в код C? - PullRequest
1 голос
/ 14 июля 2020

Для библиотеки, которую мне нужно написать, у меня есть структура, представляющая службу, написанную на C:

struct RustService {
    id: u8, /* it's me setting the id in the first place */
    service: *mut c_void,
    status: *mut c_void,
    value: Option<u32>,
    /* various fields here */
}

impl RustService {
    fn new() -> /* can be wrapped*/RustService {
       /* ... */
    }
}

У меня есть несколько обратных вызовов, переданных в C библиотеку, например:

#[no_mangle]
extern "C" fn callback_handle(service: *mut c_void, size: *mut u32, buffer: *mut u8)
{
    let id: u8 = c_library_get_id(service);
    let instance: &mut RustService = /* get that from static container based on id */

    if size = mem::size_of::<u32>() as u32 {
        let value = buffer.cast::<u32>().read();
        instance.value = Some(value);
    } else {
        panic!("Invalid length passed.");
    }
}

То, что я ищу, - это проверенная / хорошая практика, которая применима здесь, которая работает, не вызывая взаимоблокировки, когда мой обратный вызов может ссылаться на правильный экземпляр, используя библиотеку в C. Эта библиотека в C может запускать несколько экземпляров, но это не так важно. В качестве альтернативы я могу принять шаблон одного экземпляра, который будет работать в этом случае.

Другие методы RustService должны будут вызывать, например, функцию со следующей подписью (из bindgen):

extern "C" pub fn clibCoreWork(status: *mut clibStatus, service: *mut clibService) -> u32;

и внутренности этой функции могут решить вызвать эти обратные вызовы, упомянутые выше.

Подход, который я использовал, убивает меня в ногу, поскольку внутренние взаимоблокировки Mutex даже в одиночном thread:

lazy_static! {
    static ref MY_INSTANCES: Mutex<HashMap<u8, Weak<Mutex<RustService>>>> = Mutex::new(HashMap::new());
}

Я откопал inte rnet, но товарищи Rustaceans, похоже, ничего не писали о такой проблеме.

Примечание: Я не могу изменить базовый типы в библиотеке C, которую я использую. В идеальном мире это позволило бы мне хранить указатель на пользовательские данные, и я бы жестоко преобразовал его в изменяемую ссылку в небезопасном коде.

...