use crate::core::detector::condvar::create_condvar;
use crate::core::locks::condvar::Condvar;
use crate::ffi::FFI_GUARD;
use std::cell::RefCell;
use std::ffi::{c_int, c_ulong, c_void};
use std::time::Duration;
thread_local! {
static FFI_CONDVAR_WAIT_STATE: RefCell<Option<(*mut c_void, *mut c_void)>> = const { RefCell::new(None) };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn deloxide_create_condvar() -> *mut c_void {
let condvar = Box::new(Condvar::new());
Box::into_raw(condvar) as *mut c_void
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn deloxide_create_condvar_with_creator(
_creator_thread_id: usize,
) -> *mut c_void {
let condvar = Box::new(Condvar::new());
create_condvar(condvar.id());
Box::into_raw(condvar) as *mut c_void
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn deloxide_destroy_condvar(condvar: *mut c_void) {
if condvar.is_null() {
return;
}
let _condvar: Box<Condvar> = unsafe { Box::from_raw(condvar as *mut Condvar) };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn deloxide_condvar_wait(condvar: *mut c_void, mutex: *mut c_void) -> c_int {
if condvar.is_null() {
return -1;
}
if mutex.is_null() {
return -2;
}
let condvar_ref = unsafe { &*(condvar as *const Condvar) };
let mut guard = match FFI_GUARD.with(|map| map.borrow_mut().remove(&mutex)) {
Some(guard) => guard,
None => return -3, };
FFI_CONDVAR_WAIT_STATE.with(|cell| {
*cell.borrow_mut() = Some((condvar, mutex));
});
condvar_ref.wait(&mut guard);
FFI_GUARD.with(|map| {
map.borrow_mut().insert(mutex, guard);
});
FFI_CONDVAR_WAIT_STATE.with(|cell| {
*cell.borrow_mut() = None;
});
0
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn deloxide_condvar_wait_timeout(
condvar: *mut c_void,
mutex: *mut c_void,
timeout_ms: c_ulong,
) -> c_int {
if condvar.is_null() {
return -1;
}
if mutex.is_null() {
return -2;
}
let condvar_ref = unsafe { &*(condvar as *const Condvar) };
let mut guard = match FFI_GUARD.with(|map| map.borrow_mut().remove(&mutex)) {
Some(guard) => guard,
None => return -3, };
FFI_CONDVAR_WAIT_STATE.with(|cell| {
*cell.borrow_mut() = Some((condvar, mutex));
});
let timeout = Duration::from_millis(timeout_ms);
let timed_out = condvar_ref.wait_timeout(&mut guard, timeout);
FFI_GUARD.with(|map| {
map.borrow_mut().insert(mutex, guard);
});
FFI_CONDVAR_WAIT_STATE.with(|cell| {
*cell.borrow_mut() = None;
});
if timed_out {
1 } else {
0 }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn deloxide_condvar_notify_one(condvar: *mut c_void) -> c_int {
if condvar.is_null() {
return -1;
}
let condvar_ref = unsafe { &*(condvar as *const Condvar) };
condvar_ref.notify_one();
0
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn deloxide_condvar_notify_all(condvar: *mut c_void) -> c_int {
if condvar.is_null() {
return -1;
}
let condvar_ref = unsafe { &*(condvar as *const Condvar) };
condvar_ref.notify_all();
0
}