Replace lazy_static Lua Shared struct with a much faster single-threaded abstraction
This commit is contained in:
parent
50f1bcb851
commit
8d0bacec52
|
@ -109,7 +109,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gmod"
|
name = "gmod"
|
||||||
version = "5.0.0"
|
version = "6.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg_table",
|
"cfg_table",
|
||||||
"cstr",
|
"cstr",
|
||||||
|
@ -127,7 +127,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gmod-macros"
|
name = "gmod-macros"
|
||||||
version = "0.1.0"
|
version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
|
@ -8,6 +8,15 @@ A swiss army knife for creating binary modules for Garry's Mod in Rust.
|
||||||
|
|
||||||
# Example
|
# 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
|
### Cargo.toml
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "gmod-macros"
|
name = "gmod-macros"
|
||||||
version = "0.1.0"
|
version = "1.0.0"
|
||||||
authors = ["William Venner <william@venner.io>"]
|
authors = ["William Venner <william@venner.io>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
|
@ -21,6 +21,7 @@ fn check_lua_function(input: &mut ItemFn) {
|
||||||
pub fn gmod13_open(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
|
pub fn gmod13_open(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
|
||||||
let mut input = parse_macro_input!(tokens as ItemFn);
|
let mut input = parse_macro_input!(tokens as ItemFn);
|
||||||
check_lua_function(&mut input);
|
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))
|
TokenStream::from(quote!(#[no_mangle] #input))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "gmod"
|
name = "gmod"
|
||||||
version = "5.0.0"
|
version = "6.0.0"
|
||||||
authors = ["William Venner <william@venner.io>"]
|
authors = ["William Venner <william@venner.io>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
@ -16,7 +16,7 @@ skidscan = "0"
|
||||||
cstr = "0"
|
cstr = "0"
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
ctor = "0"
|
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_type_alias = "0"
|
||||||
fn_abi = "2"
|
fn_abi = "2"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#![doc = include_str!("../../README.md")]
|
#![doc = include_str!("../../README.md")]
|
||||||
#![feature(c_unwind)]
|
#![feature(c_unwind)]
|
||||||
|
#![feature(thread_id_value)]
|
||||||
|
|
||||||
pub use libloading;
|
pub use libloading;
|
||||||
pub use detour;
|
pub use detour;
|
||||||
|
|
|
@ -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};
|
use libloading::{Library, Symbol};
|
||||||
|
|
||||||
|
@ -70,9 +73,49 @@ impl LuaError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
#[cfg_attr(not(debug_assertions), repr(transparent))]
|
||||||
pub static ref LUA_SHARED: LuaShared = LuaShared::import();
|
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 struct LuaShared {
|
||||||
pub lual_newstate: Symbol<'static, unsafe extern "C-unwind" fn() -> LuaState>,
|
pub lual_newstate: Symbol<'static, unsafe extern "C-unwind" fn() -> LuaState>,
|
||||||
|
|
|
@ -93,4 +93,10 @@ pub struct LuaDebug {
|
||||||
pub lastlinedefined: i32,
|
pub lastlinedefined: i32,
|
||||||
pub short_src: [std::os::raw::c_char; LUA_IDSIZE],
|
pub short_src: [std::os::raw::c_char; LUA_IDSIZE],
|
||||||
pub i_ci: i32
|
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()
|
||||||
}
|
}
|
Loading…
Reference in New Issue