Make LuaHook as Fn instead of FnMut to remove Mutex and improve performance
This commit is contained in:
parent
595bc3a2b3
commit
4492a20bbc
21
src/lua.rs
21
src/lua.rs
|
@ -868,7 +868,7 @@ impl Lua {
|
||||||
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
|
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
|
||||||
pub fn set_hook<F>(&self, triggers: HookTriggers, callback: F) -> Result<()>
|
pub fn set_hook<F>(&self, triggers: HookTriggers, callback: F) -> Result<()>
|
||||||
where
|
where
|
||||||
F: 'static + MaybeSend + FnMut(&Lua, Debug) -> Result<()>,
|
F: 'static + MaybeSend + Fn(&Lua, Debug) -> Result<()>,
|
||||||
{
|
{
|
||||||
unsafe extern "C" fn hook_proc(state: *mut ffi::lua_State, ar: *mut ffi::lua_Debug) {
|
unsafe extern "C" fn hook_proc(state: *mut ffi::lua_State, ar: *mut ffi::lua_Debug) {
|
||||||
let lua = match Lua::make_from_ptr(state) {
|
let lua = match Lua::make_from_ptr(state) {
|
||||||
|
@ -880,29 +880,24 @@ impl Lua {
|
||||||
let debug = Debug::new(&lua, ar);
|
let debug = Debug::new(&lua, ar);
|
||||||
let hook_cb = (*lua.extra.get()).hook_callback.clone();
|
let hook_cb = (*lua.extra.get()).hook_callback.clone();
|
||||||
let hook_cb = mlua_expect!(hook_cb, "no hook callback set in hook_proc");
|
let hook_cb = mlua_expect!(hook_cb, "no hook callback set in hook_proc");
|
||||||
|
if Arc::strong_count(&hook_cb) > 2 {
|
||||||
#[allow(clippy::match_wild_err_arm)]
|
return Ok(()); // Don't allow recursion
|
||||||
match hook_cb.try_lock() {
|
|
||||||
Ok(mut cb) => cb(&lua, debug),
|
|
||||||
Err(_) => {
|
|
||||||
mlua_panic!("Lua should not allow hooks to be called within another hook")
|
|
||||||
}
|
}
|
||||||
}?;
|
hook_cb(&lua, debug)
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let state = self.main_state.ok_or(Error::MainThreadNotAvailable)?;
|
let state = self.main_state.ok_or(Error::MainThreadNotAvailable)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
(*self.extra.get()).hook_callback = Some(Arc::new(Mutex::new(callback)));
|
(*self.extra.get()).hook_callback = Some(Arc::new(callback));
|
||||||
ffi::lua_sethook(state, Some(hook_proc), triggers.mask(), triggers.count());
|
ffi::lua_sethook(state, Some(hook_proc), triggers.mask(), triggers.count());
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove any hook previously set by `set_hook`. This function has no effect if a hook was not
|
/// Removes any hook previously set by `set_hook`.
|
||||||
/// previously set.
|
///
|
||||||
|
/// This function has no effect if a hook was not previously set.
|
||||||
#[cfg(not(feature = "luau"))]
|
#[cfg(not(feature = "luau"))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
|
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
|
||||||
pub fn remove_hook(&self) {
|
pub fn remove_hook(&self) {
|
||||||
|
|
|
@ -15,6 +15,10 @@ pub use crate::{
|
||||||
Value as LuaValue,
|
Value as LuaValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "luau"))]
|
||||||
|
#[doc(no_inline)]
|
||||||
|
pub use crate::HookTriggers as LuaHookTriggers;
|
||||||
|
|
||||||
#[cfg(feature = "luau")]
|
#[cfg(feature = "luau")]
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use crate::VmState as LuaVmState;
|
pub use crate::VmState as LuaVmState;
|
||||||
|
|
13
src/types.rs
13
src/types.rs
|
@ -49,13 +49,8 @@ pub(crate) struct AsyncPollUpvalue<'lua> {
|
||||||
pub(crate) lua: Lua,
|
pub(crate) lua: Lua,
|
||||||
pub(crate) fut: LocalBoxFuture<'lua, Result<MultiValue<'lua>>>,
|
pub(crate) fut: LocalBoxFuture<'lua, Result<MultiValue<'lua>>>,
|
||||||
}
|
}
|
||||||
#[cfg(all(feature = "send", not(feature = "luau")))]
|
|
||||||
pub(crate) type HookCallback = Arc<Mutex<dyn FnMut(&Lua, Debug) -> Result<()> + Send>>;
|
|
||||||
|
|
||||||
#[cfg(all(not(feature = "send"), not(feature = "luau")))]
|
/// Type to set next Luau VM action after executing interrupt function.
|
||||||
pub(crate) type HookCallback = Arc<Mutex<dyn FnMut(&Lua, Debug) -> Result<()>>>;
|
|
||||||
|
|
||||||
/// Type to set next Lua VM action after executing interrupt function.
|
|
||||||
#[cfg(any(feature = "luau", doc))]
|
#[cfg(any(feature = "luau", doc))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
|
||||||
pub enum VmState {
|
pub enum VmState {
|
||||||
|
@ -63,6 +58,12 @@ pub enum VmState {
|
||||||
Yield,
|
Yield,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "send", not(feature = "luau")))]
|
||||||
|
pub(crate) type HookCallback = Arc<dyn Fn(&Lua, Debug) -> Result<()> + Send>;
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "send"), not(feature = "luau")))]
|
||||||
|
pub(crate) type HookCallback = Arc<dyn Fn(&Lua, Debug) -> Result<()>>;
|
||||||
|
|
||||||
#[cfg(all(feature = "luau", feature = "send"))]
|
#[cfg(all(feature = "luau", feature = "send"))]
|
||||||
pub(crate) type InterruptCallback = Arc<dyn Fn(&Lua) -> Result<VmState> + Send>;
|
pub(crate) type InterruptCallback = Arc<dyn Fn(&Lua) -> Result<VmState> + Send>;
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
use std::sync::atomic::{AtomicI64, Ordering};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use mlua::{DebugEvent, Error, HookTriggers, Lua, Result, Value};
|
use mlua::{DebugEvent, Error, HookTriggers, Lua, Result, Value};
|
||||||
|
@ -128,18 +129,17 @@ fn test_error_within_hook() -> Result<()> {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_limit_execution_instructions() -> Result<()> {
|
fn test_limit_execution_instructions() -> Result<()> {
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
let mut max_instructions = 10000;
|
|
||||||
|
|
||||||
#[cfg(feature = "luajit")]
|
|
||||||
// For LuaJIT disable JIT, as compiled code does not trigger hooks
|
// For LuaJIT disable JIT, as compiled code does not trigger hooks
|
||||||
|
#[cfg(feature = "luajit")]
|
||||||
lua.load("jit.off()").exec()?;
|
lua.load("jit.off()").exec()?;
|
||||||
|
|
||||||
|
let max_instructions = AtomicI64::new(10000);
|
||||||
lua.set_hook(
|
lua.set_hook(
|
||||||
HookTriggers::every_nth_instruction(30),
|
HookTriggers::every_nth_instruction(30),
|
||||||
move |_lua, debug| {
|
move |_lua, debug| {
|
||||||
assert_eq!(debug.event(), DebugEvent::Count);
|
assert_eq!(debug.event(), DebugEvent::Count);
|
||||||
max_instructions -= 30;
|
if max_instructions.fetch_sub(30, Ordering::Relaxed) <= 30 {
|
||||||
if max_instructions < 0 {
|
|
||||||
Err(Error::RuntimeError("time's up".to_string()))
|
Err(Error::RuntimeError("time's up".to_string()))
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in New Issue