use std::{
cell::RefCell,
thread::{Thread, current},
};
use log::error;
use crate::{
JavaVM,
errors::*,
vm::java_vm::{
AttachConfig, AttachGuard, sys_attach_current_thread, sys_detach_current_thread,
},
};
thread_local! {
#[cfg_attr(target_os = "android", allow(clippy::missing_const_for_thread_local))]
static TLS_ATTACH_GUARD: RefCell<Option<TLSAttachGuard>> = const { RefCell::new(None) }
}
#[derive(Debug)]
struct TLSAttachGuard {
thread: Thread,
}
impl TLSAttachGuard {
unsafe fn detach_impl(&self) -> Result<()> {
unsafe { sys_detach_current_thread(None, &self.thread) }
}
}
impl Drop for TLSAttachGuard {
fn drop(&mut self) {
if let Err(e) = unsafe { self.detach_impl() } {
error!(
"Error detaching current thread: {:#?}\nThread {} id={:?}",
e,
self.thread.name().unwrap_or_default(),
self.thread.id(),
);
}
}
}
pub(super) unsafe fn tls_attach_current_thread<'local>(
java_vm: &JavaVM,
config: &AttachConfig,
) -> Result<AttachGuard<'local>> {
let thread = current();
let env = TLS_ATTACH_GUARD.with(move |f| -> jni::errors::Result<*mut jni::sys::JNIEnv> {
let inc_attached_count = if let Some(guard) = f.borrow_mut().take() {
std::mem::forget(guard);
false
} else {
true
};
let env =
unsafe { sys_attach_current_thread(java_vm, config, &thread, inc_attached_count)? };
*f.borrow_mut() = Some(TLSAttachGuard { thread: current() });
Ok(env)
})?;
Ok(unsafe { AttachGuard::from_unowned(env) })
}
pub(super) fn tls_detach_current_thread() -> Result<()> {
if JavaVM::thread_attach_guard_level() != 0 {
return Err(Error::ThreadAttachmentGuarded);
}
TLS_ATTACH_GUARD.with(move |f| {
if let Some(guard) = f.borrow_mut().take() {
let res = unsafe { guard.detach_impl() };
std::mem::forget(guard);
res
} else {
Ok(())
}
})
}