binaryninja/
main_thread.rs

1use crate::rc::{Ref, RefCountable};
2use binaryninjacore_sys::{
3    BNExecuteMainThreadAction, BNExecuteOnMainThread, BNExecuteOnMainThreadAndWait,
4    BNFreeMainThreadAction, BNIsMainThreadActionDone, BNMainThreadAction, BNMainThreadCallbacks,
5    BNNewMainThreadActionReference, BNRegisterMainThread, BNWaitForMainThreadAction,
6};
7use std::ffi::c_void;
8
9pub struct MainThreadActionExecutor {
10    func: Box<dyn Fn()>,
11}
12
13impl MainThreadActionExecutor {
14    unsafe extern "C" fn cb_execute(ctx: *mut c_void) {
15        let f: Box<Self> = Box::from_raw(ctx as *mut Self);
16        f.execute();
17    }
18
19    pub fn execute(&self) {
20        (self.func)();
21    }
22}
23
24/// Execute passed function on the main thread. Returns `None` if already running on the main thread.
25///
26/// When not running in headless this will block the UI.
27pub fn execute_on_main_thread<F: Fn() + 'static>(f: F) -> Option<Ref<MainThreadAction>> {
28    let boxed_executor = Box::new(MainThreadActionExecutor { func: Box::new(f) });
29    let raw_executor = Box::into_raw(boxed_executor);
30    let raw_action = unsafe {
31        BNExecuteOnMainThread(
32            raw_executor as *mut c_void,
33            Some(MainThreadActionExecutor::cb_execute),
34        )
35    };
36    match raw_action.is_null() {
37        false => Some(MainThreadAction::ref_from_raw(raw_action)),
38        true => None,
39    }
40}
41
42/// Execute passed function on the main thread and wait until the function is finished.
43///
44/// When not running in headless this will block the UI.
45pub fn execute_on_main_thread_and_wait<F: Fn() + 'static>(f: F) {
46    let boxed_executor = Box::new(MainThreadActionExecutor { func: Box::new(f) });
47    let raw_executor = Box::into_raw(boxed_executor);
48    unsafe {
49        BNExecuteOnMainThreadAndWait(
50            raw_executor as *mut c_void,
51            Some(MainThreadActionExecutor::cb_execute),
52        )
53    };
54}
55
56/// The trait required for receiving main thread actions
57pub trait MainThreadHandler: Sized {
58    fn add_action(&self, _view: Ref<MainThreadAction>);
59
60    unsafe extern "C" fn cb_add_action(ctxt: *mut c_void, action: *mut BNMainThreadAction) {
61        ffi_wrap!("MainThread::add_action", {
62            let main_thread = &*(ctxt as *mut Self);
63            let action = MainThreadAction::ref_from_raw(action);
64            main_thread.add_action(action);
65        })
66    }
67
68    /// Register the main thread handler. Leaking [`Self`] in the process.
69    ///
70    /// NOTE: This MUST be called from **within** the main thread.
71    fn register(self) {
72        // NOTE: We leak self here.
73        let raw = Box::into_raw(Box::new(self));
74        let mut callbacks = BNMainThreadCallbacks {
75            context: raw as *mut c_void,
76            addAction: Some(Self::cb_add_action),
77        };
78        unsafe { BNRegisterMainThread(&mut callbacks) };
79    }
80}
81
82pub struct MainThreadAction {
83    pub handle: *mut BNMainThreadAction,
84}
85
86impl MainThreadAction {
87    pub fn from_raw(handle: *mut BNMainThreadAction) -> Self {
88        assert!(!handle.is_null());
89        Self { handle }
90    }
91
92    pub fn ref_from_raw(handle: *mut BNMainThreadAction) -> Ref<Self> {
93        unsafe { Ref::new(Self::from_raw(handle)) }
94    }
95
96    pub fn execute(&self) {
97        unsafe { BNExecuteMainThreadAction(self.handle) }
98    }
99
100    pub fn is_done(&self) -> bool {
101        unsafe { BNIsMainThreadActionDone(self.handle) }
102    }
103
104    pub fn wait(&self) {
105        unsafe { BNWaitForMainThreadAction(self.handle) }
106    }
107}
108
109impl ToOwned for MainThreadAction {
110    type Owned = Ref<Self>;
111
112    fn to_owned(&self) -> Self::Owned {
113        unsafe { RefCountable::inc_ref(self) }
114    }
115}
116
117unsafe impl RefCountable for MainThreadAction {
118    unsafe fn inc_ref(action: &Self) -> Ref<Self> {
119        Ref::new(Self {
120            handle: BNNewMainThreadActionReference(action.handle),
121        })
122    }
123
124    unsafe fn dec_ref(action: &Self) {
125        BNFreeMainThreadAction(action.handle);
126    }
127}
128
129unsafe impl Send for MainThreadAction {}