use super::super::api;
#[cfg(dev_release)]
use crate::logger;
use std::ffi::c_void;
use std::ptr;
pub struct Thread {
thread_ptr: *mut c_void,
auto_detach: bool,
}
impl Thread {
pub unsafe fn from_ptr(thread_ptr: *mut c_void, auto_detach: bool) -> Self {
Self {
thread_ptr,
auto_detach,
}
}
pub fn as_ptr(&self) -> *mut c_void {
self.thread_ptr
}
pub fn detach(mut self) {
if !self.thread_ptr.is_null() {
unsafe {
api::thread_detach(self.thread_ptr);
}
#[cfg(dev_release)]
logger::info("Thread manually detached from IL2CPP");
self.thread_ptr = ptr::null_mut();
}
self.auto_detach = false;
}
pub fn is_vm_thread(&self) -> bool {
if self.thread_ptr.is_null() {
return false;
}
unsafe { api::is_vm_thread(self.thread_ptr) }
}
pub fn current() -> Option<Self> {
unsafe {
let current = api::thread_current();
if !current.is_null() {
Some(Self::from_ptr(current, false))
} else {
None
}
}
}
pub fn attach(auto_detach: bool) -> Option<Self> {
unsafe {
if Self::is_attached() {
#[cfg(dev_release)]
logger::info("Thread already attached to IL2CPP, returning existing thread");
return Self::current();
}
let domain_ptr = api::domain_get();
if domain_ptr.is_null() {
#[cfg(dev_release)]
logger::error("Failed to get IL2CPP domain for thread attachment");
return None;
}
let thread_ptr = api::thread_attach(domain_ptr);
if thread_ptr.is_null() {
#[cfg(dev_release)]
logger::error("Failed to attach thread to IL2CPP");
None
} else {
#[cfg(dev_release)]
logger::info("Thread successfully attached to IL2CPP");
Some(Self::from_ptr(thread_ptr, auto_detach))
}
}
}
pub fn is_attached() -> bool {
unsafe {
let current = api::thread_current();
!current.is_null()
}
}
pub fn all() -> Vec<Thread> {
unsafe {
let mut size: usize = 0;
let threads_ptr = api::thread_get_all_attached_threads(&mut size as *mut usize);
if threads_ptr.is_null() || size == 0 {
return Vec::new();
}
let mut threads = Vec::with_capacity(size);
for i in 0..size {
let thread_ptr = *threads_ptr.add(i);
if !thread_ptr.is_null() {
threads.push(Thread::from_ptr(thread_ptr, false));
}
}
threads
}
}
}
impl Drop for Thread {
fn drop(&mut self) {
if self.auto_detach && !self.thread_ptr.is_null() {
unsafe {
api::thread_detach(self.thread_ptr);
}
#[cfg(dev_release)]
logger::info("Thread automatically detached from IL2CPP");
self.thread_ptr = ptr::null_mut();
}
}
}
unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}