diff options
author | Alex Orlenko <zxteam@protonmail.com> | 2020-04-23 21:29:12 +0100 |
---|---|---|
committer | Alex Orlenko <zxteam@protonmail.com> | 2020-04-28 14:29:14 +0100 |
commit | fe5e87b0f5e4d017a6b8c02d8223d7d8dd9671cc (patch) | |
tree | 03d68817ba9bf628862027a9f9520c4f5544364e | |
parent | 0f32e9cb43acdcc7d7b7d59dfc3da7ccac459d18 (diff) | |
download | mlua-fe5e87b0f5e4d017a6b8c02d8223d7d8dd9671cc.zip |
Fix bugs with metatable cache:
- Don't use thread_local as Lua can be created in one thread and executed in another (in module mode);
- Make per state storage without luaL_ref;
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/util.rs | 28 |
2 files changed, 21 insertions, 8 deletions
@@ -38,6 +38,7 @@ async = ["futures-core", "futures-task", "futures-util"] [dependencies] bstr = { version = "0.2", features = ["std"], default_features = false } +lazy_static = { version = "1.4" } num-traits = { version = "0.2.11" } futures-core = { version = "0.3.4", optional = true } futures-task = { version = "0.3.4", optional = true } diff --git a/src/util.rs b/src/util.rs index 88e3fe0..5d71cbf 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,18 +1,19 @@ use std::any::{Any, TypeId}; use std::borrow::Cow; -use std::cell::RefCell; use std::collections::HashMap; use std::fmt::Write; use std::os::raw::{c_char, c_int, c_void}; use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; use std::rc::Rc; +use std::sync::Mutex; use std::{mem, ptr, slice}; use crate::error::{Error, Result}; use crate::ffi; -thread_local! { - static METATABLE_CACHE: RefCell<HashMap<TypeId, c_int>> = RefCell::new(HashMap::new()); +lazy_static::lazy_static! { + // The capacity must(!) be greater than number of stored keys + static ref METATABLE_CACHE: Mutex<HashMap<TypeId, u8>> = Mutex::new(HashMap::with_capacity(32)); } // Checks that Lua has enough free stack space for future stack operations. On failure, this will @@ -519,6 +520,16 @@ pub unsafe fn init_gc_metatable_for<T: Any>( ) { let type_id = TypeId::of::<T>(); + let ref_addr = { + let mut mt_cache = mlua_expect!(METATABLE_CACHE.lock(), "cannot lock metatable cache"); + mlua_assert!( + mt_cache.capacity() - mt_cache.len() > 0, + "out of metatable cache capacity" + ); + mt_cache.insert(type_id, 0); + &mt_cache[&type_id] as *const u8 + }; + ffi::lua_newtable(state); ffi::lua_pushstring(state, cstr!("__gc")); @@ -533,15 +544,16 @@ pub unsafe fn init_gc_metatable_for<T: Any>( f(state) } - let ref_addr = ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX); - METATABLE_CACHE.with(|mc| mc.borrow_mut().insert(type_id, ref_addr)); + ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, ref_addr as *mut c_void); } pub unsafe fn get_gc_metatable_for<T: Any>(state: *mut ffi::lua_State) { let type_id = TypeId::of::<T>(); - let ref_addr = METATABLE_CACHE - .with(|mc| *mlua_expect!(mc.borrow().get(&type_id), "gc metatable does not exist")); - ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, ref_addr as ffi::lua_Integer); + let ref_addr = { + let mt_cache = mlua_expect!(METATABLE_CACHE.lock(), "cannot lock metatable cache"); + mlua_expect!(mt_cache.get(&type_id), "gc metatable does not exist") as *const u8 + }; + ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, ref_addr as *mut c_void); } // Initialize the error, panic, and destructed userdata metatables. |