Add `Thread::reset()` for luajit/lua54
This commit is contained in:
parent
7541b6f3f3
commit
5293b8d6d2
|
@ -156,8 +156,13 @@ extern "C" {
|
|||
pub fn lua_newstate(f: lua_Alloc, ud: *mut c_void) -> *mut lua_State;
|
||||
pub fn lua_close(L: *mut lua_State);
|
||||
pub fn lua_newthread(L: *mut lua_State) -> *mut lua_State;
|
||||
|
||||
#[cfg(feature = "lua54")]
|
||||
pub fn lua_resetthread(L: *mut lua_State) -> c_int;
|
||||
#[link_name = "lua_resetthread"]
|
||||
pub fn lua_resetthread_54(L: *mut lua_State) -> c_int;
|
||||
#[cfg(all(feature = "luajit", feature = "vendored"))]
|
||||
#[link_name = "lua_resetthread"]
|
||||
pub fn lua_resetthread_jit(L: *mut lua_State, th: *mut lua_State);
|
||||
|
||||
pub fn lua_atpanic(L: *mut lua_State, panicf: lua_CFunction) -> lua_CFunction;
|
||||
|
||||
|
@ -216,6 +221,17 @@ extern "C" {
|
|||
pub fn lua_topointer(L: *mut lua_State, idx: c_int) -> *const c_void;
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua54", all(feature = "luajit", feature = "vendored")))]
|
||||
pub unsafe fn lua_resetthread(_L: *mut lua_State, th: *mut lua_State) -> c_int {
|
||||
#[cfg(all(feature = "luajit", feature = "vendored"))]
|
||||
{
|
||||
lua_resetthread_jit(_L, th);
|
||||
LUA_OK
|
||||
}
|
||||
#[cfg(feature = "lua54")]
|
||||
lua_resetthread_54(th)
|
||||
}
|
||||
|
||||
// Comparison and arithmetic functions
|
||||
pub const LUA_OPADD: c_int = 0;
|
||||
pub const LUA_OPSUB: c_int = 1;
|
||||
|
|
|
@ -160,8 +160,8 @@ pub use self::lua::{
|
|||
|
||||
#[cfg(feature = "lua54")]
|
||||
pub use self::lua::{
|
||||
lua_getiuservalue, lua_newuserdatauv, lua_resetthread, lua_setcstacklimit, lua_setiuservalue,
|
||||
lua_setwarnf, lua_toclose, lua_warning,
|
||||
lua_getiuservalue, lua_newuserdatauv, lua_setcstacklimit, lua_setiuservalue, lua_setwarnf,
|
||||
lua_toclose, lua_warning,
|
||||
};
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
|
@ -170,6 +170,9 @@ pub use self::lua::{lua_isyieldable, lua_version};
|
|||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||
pub use self::lua::{lua_callk, lua_pcallk, lua_upvalueid, lua_upvaluejoin, lua_yieldk};
|
||||
|
||||
#[cfg(any(feature = "lua54", all(feature = "luajit", feature = "vendored")))]
|
||||
pub use self::lua::lua_resetthread;
|
||||
|
||||
// auxiliary library types
|
||||
pub use self::lauxlib::luaL_Reg;
|
||||
|
||||
|
|
|
@ -7,6 +7,9 @@ use crate::types::LuaRef;
|
|||
use crate::util::{assert_stack, check_stack, pop_error, StackGuard};
|
||||
use crate::value::{FromLuaMulti, MultiValue, ToLuaMulti};
|
||||
|
||||
#[cfg(any(feature = "lua54", all(feature = "luajit", feature = "vendored"), doc))]
|
||||
use crate::function::Function;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
use {
|
||||
crate::{
|
||||
|
@ -170,6 +173,43 @@ impl<'lua> Thread<'lua> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Resets a thread
|
||||
///
|
||||
/// In [Lua 5.4]: cleans its call stack and closes all pending to-be-closed variables.
|
||||
/// Returns a error in case of either the original error that stopped the thread or errors
|
||||
/// in closing methods.
|
||||
///
|
||||
/// In [LuaJIT]: resets to the initial state of a newly created Lua thread.
|
||||
/// Lua threads in arbitrary states (like yielded or errored) can be reset properly.
|
||||
///
|
||||
/// Sets a Lua function for the thread afterwards.
|
||||
///
|
||||
/// Requires `feature = "lua54"` OR `feature = "luajit,vendored"`
|
||||
///
|
||||
/// [Lua 5.4]: https://www.lua.org/manual/5.4/manual.html#lua_resetthread
|
||||
/// [LuaJIT]: https://github.com/openresty/luajit2#lua_resetthread
|
||||
#[cfg(any(feature = "lua54", all(feature = "luajit", feature = "vendored"), doc))]
|
||||
pub fn reset(&self, func: Function<'lua>) -> Result<()> {
|
||||
let lua = self.0.lua;
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
check_stack(lua.state, 2)?;
|
||||
|
||||
lua.push_ref(&self.0);
|
||||
let thread_state = ffi::lua_tothread(lua.state, -1);
|
||||
|
||||
let ret = ffi::lua_resetthread(lua.state, thread_state);
|
||||
if ret != ffi::LUA_OK {
|
||||
return Err(pop_error(thread_state, ret));
|
||||
}
|
||||
|
||||
lua.push_ref(&func.0);
|
||||
ffi::lua_xmove(lua.state, thread_state, 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts Thread to an AsyncThread which implements Future and Stream traits.
|
||||
///
|
||||
/// `args` are passed as arguments to the thread function for first call.
|
||||
|
|
|
@ -21,7 +21,10 @@ use crate::lua::Lua;
|
|||
use crate::table::{Table, TablePairs};
|
||||
use crate::types::{LuaRef, MaybeSend};
|
||||
use crate::util::{check_stack, get_destructed_userdata_metatable, get_userdata, StackGuard};
|
||||
use crate::value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti, Value};
|
||||
use crate::value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti};
|
||||
|
||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||
use crate::value::Value;
|
||||
|
||||
/// Kinds of metamethods that can be overridden.
|
||||
///
|
||||
|
|
|
@ -93,6 +93,49 @@ fn test_thread() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lua54", all(feature = "luajit", feature = "vendored")))]
|
||||
#[test]
|
||||
fn test_thread_reset() -> Result<()> {
|
||||
use mlua::{AnyUserData, UserData};
|
||||
use std::sync::Arc;
|
||||
|
||||
let lua = Lua::new();
|
||||
|
||||
struct MyUserData(Arc<()>);
|
||||
impl UserData for MyUserData {}
|
||||
|
||||
let arc = Arc::new(());
|
||||
|
||||
let func: Function = lua.load(r#"function(ud) coroutine.yield(ud) end"#).eval()?;
|
||||
let thread = lua.create_thread(func.clone())?;
|
||||
|
||||
for _ in 0..2 {
|
||||
assert_eq!(thread.status(), ThreadStatus::Resumable);
|
||||
let _ = thread.resume::<_, AnyUserData>(MyUserData(arc.clone()))?;
|
||||
assert_eq!(thread.status(), ThreadStatus::Resumable);
|
||||
assert_eq!(Arc::strong_count(&arc), 2);
|
||||
thread.resume::<_, ()>(())?;
|
||||
assert_eq!(thread.status(), ThreadStatus::Unresumable);
|
||||
thread.reset(func.clone())?;
|
||||
lua.gc_collect()?;
|
||||
assert_eq!(Arc::strong_count(&arc), 1);
|
||||
}
|
||||
|
||||
// Check for errors (Lua 5.4 only)
|
||||
#[cfg(feature = "lua54")]
|
||||
{
|
||||
let func: Function = lua.load(r#"function(ud) error("test error") end"#).eval()?;
|
||||
let thread = lua.create_thread(func.clone())?;
|
||||
let _ = thread.resume::<_, AnyUserData>(MyUserData(arc.clone()));
|
||||
assert_eq!(thread.status(), ThreadStatus::Error);
|
||||
assert_eq!(Arc::strong_count(&arc), 2);
|
||||
assert!(thread.reset(func.clone()).is_err());
|
||||
assert_eq!(thread.status(), ThreadStatus::Error);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn coroutine_from_closure() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
|
Loading…
Reference in New Issue