summaryrefslogtreecommitdiff
path: root/src/util.rs
diff options
context:
space:
mode:
authorAlex Orlenko <zxteam@protonmail.com>2020-04-23 21:29:12 +0100
committerAlex Orlenko <zxteam@protonmail.com>2020-04-28 14:29:14 +0100
commitfe5e87b0f5e4d017a6b8c02d8223d7d8dd9671cc (patch)
tree03d68817ba9bf628862027a9f9520c4f5544364e /src/util.rs
parent0f32e9cb43acdcc7d7b7d59dfc3da7ccac459d18 (diff)
downloadmlua-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;
Diffstat (limited to 'src/util.rs')
-rw-r--r--src/util.rs28
1 files changed, 20 insertions, 8 deletions
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.