sqlx_sqlite/statement/
unlock_notify.rs

1use std::ffi::c_void;
2use std::os::raw::c_int;
3use std::slice;
4use std::sync::{Condvar, Mutex};
5
6use libsqlite3_sys::{sqlite3, sqlite3_unlock_notify, SQLITE_OK};
7
8use crate::SqliteError;
9
10// Wait for unlock notification (https://www.sqlite.org/unlock_notify.html)
11pub unsafe fn wait(conn: *mut sqlite3) -> Result<(), SqliteError> {
12    let notify = Notify::new();
13
14    if sqlite3_unlock_notify(
15        conn,
16        Some(unlock_notify_cb),
17        &notify as *const Notify as *mut Notify as *mut _,
18    ) != SQLITE_OK
19    {
20        return Err(SqliteError::new(conn));
21    }
22
23    notify.wait();
24
25    Ok(())
26}
27
28unsafe extern "C" fn unlock_notify_cb(ptr: *mut *mut c_void, len: c_int) {
29    let ptr = ptr as *mut &Notify;
30    // We don't have a choice; we can't panic and unwind into FFI here.
31    let slice = slice::from_raw_parts(ptr, usize::try_from(len).unwrap_or(0));
32
33    for notify in slice {
34        notify.fire();
35    }
36}
37
38struct Notify {
39    mutex: Mutex<bool>,
40    condvar: Condvar,
41}
42
43impl Notify {
44    fn new() -> Self {
45        Self {
46            mutex: Mutex::new(false),
47            condvar: Condvar::new(),
48        }
49    }
50
51    fn wait(&self) {
52        // We only want to wait until the lock is available again.
53        #[allow(let_underscore_lock)]
54        let _ = self
55            .condvar
56            .wait_while(self.mutex.lock().unwrap(), |fired| !*fired)
57            .unwrap();
58    }
59
60    fn fire(&self) {
61        let mut lock = self.mutex.lock().unwrap();
62        *lock = true;
63        self.condvar.notify_one();
64    }
65}