everything_ipc/wm/shared.rs
1use std::sync::{Arc, Mutex, Weak};
2
3use crate::wm::{EverythingClient, IpcError};
4
5static SHARED: Mutex<Weak<EverythingClient>> = Mutex::new(Weak::new());
6
7impl EverythingClient {
8 /// Get a globally-shared, lazily-created [`EverythingClient`].
9 ///
10 /// The first call creates and returns an [`Arc`]-wrapped client. Subsequent
11 /// calls return a clone of the same [`Arc`]. When all returned [`Arc`]s are
12 /// dropped, the underlying client (and its reply window thread) is dropped.
13 /// A new client is automatically created on the next call.
14 ///
15 /// ## Note
16 /// [`EverythingClient::query()`] will cancel the previous query.
17 /// Use with caution.
18 pub fn shared() -> Result<Arc<Self>, IpcError> {
19 let mut guard = SHARED.lock().unwrap();
20 if let Some(client) = guard.upgrade() {
21 return Ok(client);
22 }
23 let client = Arc::new(Self::new()?);
24 *guard = Arc::downgrade(&client);
25 Ok(client)
26 }
27
28 /// Quit and join the message thread of the last [`shared`](Self::shared) client instance.
29 ///
30 /// This function is meant to manually make sure the thread is exited before DLL unloading.
31 /// While `drop-join-thread` feature also works for `static`s,
32 /// it will break `thread_local`s.
33 ///
34 /// ## Safety
35 /// This function is `!Sync`. It's unlikely that you need `Sync` though.
36 pub unsafe fn shared_quit_join_thread() {
37 let mut guard = SHARED.lock().unwrap();
38 if let Some(client) = guard.upgrade() {
39 *guard = Default::default();
40 drop(guard);
41
42 // TODO: Arc::get_mut_unchecked()
43 let client = unsafe { &mut *Arc::as_ptr(&client).cast_mut() };
44 client.reply_window.quit_join_thread();
45 }
46 }
47}