Replace lazy_static Lua Shared struct with a much faster single-threaded abstraction

This commit is contained in:
William Venner 2021-10-21 15:05:01 +01:00
parent 50f1bcb851
commit 8d0bacec52
8 changed files with 68 additions and 8 deletions

4
Cargo.lock generated
View File

@ -109,7 +109,7 @@ dependencies = [
[[package]]
name = "gmod"
version = "5.0.0"
version = "6.0.0"
dependencies = [
"cfg_table",
"cstr",
@ -127,7 +127,7 @@ dependencies = [
[[package]]
name = "gmod-macros"
version = "0.1.0"
version = "1.0.0"
dependencies = [
"proc-macro2",
"quote",

View File

@ -8,6 +8,15 @@ A swiss army knife for creating binary modules for Garry's Mod in Rust.
# Example
### rust-toolchain.toml
Because we're using the [`C-unwind`](https://rust-lang.github.io/rfcs/2797-project-ffi-unwind.html) ABI, this crate must be used on a [Nightly Rust](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html) compiler.
```toml
[toolchain]
channel = "nightly"
```
### Cargo.toml
```toml

View File

@ -1,6 +1,6 @@
[package]
name = "gmod-macros"
version = "0.1.0"
version = "1.0.0"
authors = ["William Venner <william@venner.io>"]
edition = "2018"
license = "MIT"

View File

@ -21,6 +21,7 @@ fn check_lua_function(input: &mut ItemFn) {
pub fn gmod13_open(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(tokens as ItemFn);
check_lua_function(&mut input);
input.block.stmts.insert(0, syn::parse2(quote!(#[allow(unused_unsafe)] unsafe { ::gmod::lua::load() })).unwrap());
TokenStream::from(quote!(#[no_mangle] #input))
}

View File

@ -1,6 +1,6 @@
[package]
name = "gmod"
version = "5.0.0"
version = "6.0.0"
authors = ["William Venner <william@venner.io>"]
edition = "2018"
license = "MIT"
@ -16,7 +16,7 @@ skidscan = "0"
cstr = "0"
lazy_static = "1"
ctor = "0"
gmod-macros = { version = "0.1.0", path = "../gmod-macros" }
gmod-macros = { version = "1.0.0", path = "../gmod-macros" }
fn_type_alias = "0"
fn_abi = "2"

View File

@ -1,5 +1,6 @@
#![doc = include_str!("../../README.md")]
#![feature(c_unwind)]
#![feature(thread_id_value)]
pub use libloading;
pub use detour;

View File

@ -1,4 +1,7 @@
use std::ffi::c_void;
#[cfg(debug_assertions)]
use std::sync::atomic::AtomicI64;
use std::{cell::UnsafeCell, ffi::c_void};
use libloading::{Library, Symbol};
@ -70,9 +73,49 @@ impl LuaError {
}
}
lazy_static::lazy_static! {
pub static ref LUA_SHARED: LuaShared = LuaShared::import();
#[cfg_attr(not(debug_assertions), repr(transparent))]
pub struct LuaSharedInterface(UnsafeCell<*mut LuaShared>, #[cfg(debug_assertions)] AtomicI64);
impl LuaSharedInterface {
#[cfg(debug_assertions)]
fn debug_assertions(&self) {
assert!(!unsafe { *self.0.get() }.is_null(), "The Lua state has not been initialized yet. Add `#[gmod::gmod13_open]` to your module's gmod13_open function to fix this. You can also manually load the Lua state with `gmod::load_lua_state()` or `gmod::set_lua_state(*mut c_void)`");
let thread_id = u64::from(std::thread::current().id().as_u64()) as i64;
match self.1.compare_exchange(-1, thread_id, std::sync::atomic::Ordering::SeqCst, std::sync::atomic::Ordering::SeqCst) {
Ok(-1) => {}, // This is the first thread to use this Lua state.
Ok(_) => unreachable!(),
Err(remembered_thread_id) => assert_eq!(thread_id, remembered_thread_id, "Tried to access the Lua state from another thread! The Lua state is NOT thread-safe, and should only be accessed from the main thread.")
}
}
pub(super) unsafe fn load(&self) {
*self.0.get() = Box::leak(Box::new(LuaShared::import()));
}
pub(super) unsafe fn set(&self, ptr: *mut c_void) {
*self.0.get() = ptr as *mut LuaShared;
}
}
impl std::ops::Deref for LuaSharedInterface {
type Target = LuaShared;
fn deref(&self) -> &Self::Target {
#[cfg(debug_assertions)]
self.debug_assertions();
unsafe { &**self.0.get() }
}
}
impl std::ops::DerefMut for LuaSharedInterface {
fn deref_mut(&mut self) -> &mut Self::Target {
#[cfg(debug_assertions)]
self.debug_assertions();
unsafe { &mut **self.0.get_mut() }
}
}
pub static mut LUA_SHARED: LuaSharedInterface = LuaSharedInterface(UnsafeCell::new(std::ptr::null_mut()), #[cfg(debug_assertions)] AtomicI64::new(-1));
pub struct LuaShared {
pub lual_newstate: Symbol<'static, unsafe extern "C-unwind" fn() -> LuaState>,

View File

@ -93,4 +93,10 @@ pub struct LuaDebug {
pub lastlinedefined: i32,
pub short_src: [std::os::raw::c_char; LUA_IDSIZE],
pub i_ci: i32
}
#[inline(always)]
/// Loads lua_shared and imports all functions. This is already done for you if you add `#[gmod::gmod13_open]` to your `gmod13_open` function.
pub unsafe fn load() {
import::LUA_SHARED.load()
}