Skip to content

Commit 658f2a1

Browse files
committed
Support multi threads under send feature flag
1 parent c1395ab commit 658f2a1

File tree

13 files changed

+233
-113
lines changed

13 files changed

+233
-113
lines changed

src/function.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -594,9 +594,12 @@ impl IntoLua for WrappedAsyncFunction {
594594
}
595595
}
596596

597-
// #[cfg(test)]
598-
// mod assertions {
599-
// use super::*;
600-
601-
// static_assertions::assert_not_impl_any!(Function: Send);
602-
// }
597+
#[cfg(test)]
598+
mod assertions {
599+
use super::*;
600+
601+
#[cfg(not(feature = "send"))]
602+
static_assertions::assert_not_impl_any!(Function: Send);
603+
#[cfg(feature = "send")]
604+
static_assertions::assert_impl_all!(Function: Send, Sync);
605+
}

src/hook.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ use std::ops::{BitOr, BitOrAssign};
66
use std::os::raw::c_int;
77

88
use ffi::lua_Debug;
9-
use parking_lot::ReentrantMutexGuard;
109

1110
use crate::state::RawLua;
11+
use crate::types::ReentrantMutexGuard;
1212
use crate::util::{linenumber_to_usize, ptr_to_lossy_str, ptr_to_str};
1313

1414
/// Contains information about currently executing Lua code.

src/state.rs

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@ use std::marker::PhantomData;
66
use std::ops::Deref;
77
use std::os::raw::{c_int, c_void};
88
use std::panic::Location;
9+
use std::rc::Rc;
910
use std::result::Result as StdResult;
10-
use std::sync::{Arc, Weak};
1111
use std::{mem, ptr};
1212

13-
use parking_lot::{ReentrantMutex, ReentrantMutexGuard};
14-
1513
use crate::chunk::{AsChunk, Chunk};
1614
use crate::error::{Error, Result};
1715
use crate::function::Function;
@@ -24,7 +22,7 @@ use crate::table::Table;
2422
use crate::thread::Thread;
2523
use crate::types::{
2624
AppDataRef, AppDataRefMut, ArcReentrantMutexGuard, Integer, LightUserData, MaybeSend, Number,
27-
RegistryKey,
25+
ReentrantMutex, ReentrantMutexGuard, RegistryKey, XRc, XWeak,
2826
};
2927
use crate::userdata::{AnyUserData, UserData, UserDataProxy, UserDataRegistry, UserDataVariant};
3028
use crate::util::{assert_stack, check_stack, push_string, push_table, rawset_field, StackGuard};
@@ -49,11 +47,11 @@ use util::{callback_error_ext, StateGuard};
4947
/// Top level Lua struct which represents an instance of Lua VM.
5048
#[derive(Clone)]
5149
#[repr(transparent)]
52-
pub struct Lua(Arc<ReentrantMutex<RawLua>>);
50+
pub struct Lua(XRc<ReentrantMutex<RawLua>>);
5351

5452
#[derive(Clone)]
5553
#[repr(transparent)]
56-
pub(crate) struct WeakLua(Weak<ReentrantMutex<RawLua>>);
54+
pub(crate) struct WeakLua(XWeak<ReentrantMutex<RawLua>>);
5755

5856
pub(crate) struct LuaGuard(ArcReentrantMutexGuard<RawLua>);
5957

@@ -142,11 +140,6 @@ impl LuaOptions {
142140
}
143141
}
144142

145-
/// Requires `feature = "send"`
146-
#[cfg(feature = "send")]
147-
#[cfg_attr(docsrs, doc(cfg(feature = "send")))]
148-
unsafe impl Send for Lua {}
149-
150143
#[cfg(not(feature = "module"))]
151144
impl Drop for Lua {
152145
fn drop(&mut self) {
@@ -421,7 +414,8 @@ impl Lua {
421414
#[doc(hidden)]
422415
#[cfg(feature = "module")]
423416
pub fn skip_memory_check(&self, skip: bool) {
424-
unsafe { (*self.extra.get()).skip_memory_check = skip };
417+
let lua = self.lock();
418+
unsafe { (*lua.extra.get()).skip_memory_check = skip };
425419
}
426420

427421
/// Enables (or disables) sandbox mode on this Lua instance.
@@ -605,7 +599,7 @@ impl Lua {
605599
let interrupt_cb = (*extra).interrupt_callback.clone();
606600
let interrupt_cb =
607601
mlua_expect!(interrupt_cb, "no interrupt callback set in interrupt_proc");
608-
if Arc::strong_count(&interrupt_cb) > 2 {
602+
if Rc::strong_count(&interrupt_cb) > 2 {
609603
return Ok(VmState::Continue); // Don't allow recursion
610604
}
611605
let _guard = StateGuard::new((*extra).raw_lua(), state);
@@ -622,7 +616,7 @@ impl Lua {
622616
// Set interrupt callback
623617
let lua = self.lock();
624618
unsafe {
625-
(*lua.extra.get()).interrupt_callback = Some(Arc::new(callback));
619+
(*lua.extra.get()).interrupt_callback = Some(Rc::new(callback));
626620
(*ffi::lua_callbacks(lua.main_state)).interrupt = Some(interrupt_proc);
627621
}
628622
}
@@ -947,7 +941,8 @@ impl Lua {
947941
#[cfg(any(feature = "luau-jit", doc))]
948942
#[cfg_attr(docsrs, doc(cfg(feature = "luau-jit")))]
949943
pub fn enable_jit(&self, enable: bool) {
950-
unsafe { (*self.extra.get()).enable_jit = enable };
944+
let lua = self.lock();
945+
unsafe { (*lua.extra.get()).enable_jit = enable };
951946
}
952947

953948
/// Sets Luau feature flag (global setting).
@@ -1879,15 +1874,15 @@ impl Lua {
18791874

18801875
#[inline(always)]
18811876
pub(crate) fn weak(&self) -> WeakLua {
1882-
WeakLua(Arc::downgrade(&self.0))
1877+
WeakLua(XRc::downgrade(&self.0))
18831878
}
18841879
}
18851880

18861881
impl WeakLua {
18871882
#[track_caller]
18881883
#[inline(always)]
18891884
pub(crate) fn lock(&self) -> LuaGuard {
1890-
LuaGuard::new(self.0.upgrade().unwrap())
1885+
LuaGuard::new(self.0.upgrade().expect("Lua instance is destroyed"))
18911886
}
18921887

18931888
#[inline(always)]
@@ -1898,15 +1893,21 @@ impl WeakLua {
18981893

18991894
impl PartialEq for WeakLua {
19001895
fn eq(&self, other: &Self) -> bool {
1901-
Weak::ptr_eq(&self.0, &other.0)
1896+
XWeak::ptr_eq(&self.0, &other.0)
19021897
}
19031898
}
19041899

19051900
impl Eq for WeakLua {}
19061901

19071902
impl LuaGuard {
1908-
pub(crate) fn new(handle: Arc<ReentrantMutex<RawLua>>) -> Self {
1909-
Self(handle.lock_arc())
1903+
#[cfg(feature = "send")]
1904+
pub(crate) fn new(handle: XRc<ReentrantMutex<RawLua>>) -> Self {
1905+
LuaGuard(handle.lock_arc())
1906+
}
1907+
1908+
#[cfg(not(feature = "send"))]
1909+
pub(crate) fn new(handle: XRc<ReentrantMutex<RawLua>>) -> Self {
1910+
LuaGuard(handle.into_lock_arc())
19101911
}
19111912
}
19121913

@@ -1922,15 +1923,15 @@ pub(crate) mod extra;
19221923
mod raw;
19231924
pub(crate) mod util;
19241925

1925-
// #[cfg(test)]
1926-
// mod assertions {
1927-
// use super::*;
1926+
#[cfg(test)]
1927+
mod assertions {
1928+
use super::*;
19281929

1929-
// // Lua has lots of interior mutability, should not be RefUnwindSafe
1930-
// static_assertions::assert_not_impl_any!(Lua: std::panic::RefUnwindSafe);
1930+
// Lua has lots of interior mutability, should not be RefUnwindSafe
1931+
static_assertions::assert_not_impl_any!(Lua: std::panic::RefUnwindSafe);
19311932

1932-
// #[cfg(not(feature = "send"))]
1933-
// static_assertions::assert_not_impl_any!(Lua: Send);
1934-
// #[cfg(feature = "send")]
1935-
// static_assertions::assert_impl_all!(Lua: Send);
1936-
// }
1933+
#[cfg(not(feature = "send"))]
1934+
static_assertions::assert_not_impl_any!(Lua: Send);
1935+
#[cfg(feature = "send")]
1936+
static_assertions::assert_impl_all!(Lua: Send, Sync);
1937+
}

src/state/extra.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ use std::rc::Rc;
55
use std::mem::{self, MaybeUninit};
66
use std::os::raw::{c_int, c_void};
77
use std::ptr;
8-
use std::sync::{Arc, Weak};
8+
use std::sync::Arc;
99

10-
use parking_lot::{Mutex, ReentrantMutex};
10+
use parking_lot::Mutex;
1111
use rustc_hash::FxHashMap;
1212

1313
use crate::error::Result;
1414
use crate::state::RawLua;
1515
use crate::stdlib::StdLib;
16-
use crate::types::AppData;
16+
use crate::types::{AppData, ReentrantMutex, XRc, XWeak};
1717
use crate::util::{get_gc_metatable, push_gc_userdata, WrappedFailure};
1818

1919
#[cfg(any(feature = "luau", doc))]
@@ -34,9 +34,9 @@ const REF_STACK_RESERVE: c_int = 1;
3434
/// Data associated with the Lua state.
3535
pub(crate) struct ExtraData {
3636
// Same layout as `Lua`
37-
pub(super) lua: MaybeUninit<Arc<ReentrantMutex<RawLua>>>,
37+
pub(super) lua: MaybeUninit<XRc<ReentrantMutex<RawLua>>>,
3838
// Same layout as `WeakLua`
39-
pub(super) weak: MaybeUninit<Weak<ReentrantMutex<RawLua>>>,
39+
pub(super) weak: MaybeUninit<XWeak<ReentrantMutex<RawLua>>>,
4040

4141
pub(super) registered_userdata: FxHashMap<TypeId, c_int>,
4242
pub(super) registered_userdata_mt: FxHashMap<*const c_void, Option<TypeId>>,
@@ -107,7 +107,7 @@ impl ExtraData {
107107
#[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
108108
pub(super) const ERROR_TRACEBACK_IDX: c_int = 1;
109109

110-
pub(super) unsafe fn init(state: *mut ffi::lua_State) -> Rc<UnsafeCell<Self>> {
110+
pub(super) unsafe fn init(state: *mut ffi::lua_State) -> XRc<UnsafeCell<Self>> {
111111
// Create ref stack thread and place it in the registry to prevent it
112112
// from being garbage collected.
113113
let ref_thread = mlua_expect!(
@@ -133,7 +133,7 @@ impl ExtraData {
133133
assert_eq!(ffi::lua_gettop(ref_thread), Self::ERROR_TRACEBACK_IDX);
134134
}
135135

136-
let extra = Rc::new(UnsafeCell::new(ExtraData {
136+
let extra = XRc::new(UnsafeCell::new(ExtraData {
137137
lua: MaybeUninit::uninit(),
138138
weak: MaybeUninit::uninit(),
139139
registered_userdata: FxHashMap::default(),
@@ -179,12 +179,12 @@ impl ExtraData {
179179
extra
180180
}
181181

182-
pub(super) unsafe fn set_lua(&mut self, lua: &Arc<ReentrantMutex<RawLua>>) {
183-
self.lua.write(Arc::clone(lua));
182+
pub(super) unsafe fn set_lua(&mut self, lua: &XRc<ReentrantMutex<RawLua>>) {
183+
self.lua.write(XRc::clone(lua));
184184
if cfg!(not(feature = "module")) {
185-
Arc::decrement_strong_count(Arc::as_ptr(lua));
185+
XRc::decrement_strong_count(XRc::as_ptr(lua));
186186
}
187-
self.weak.write(Arc::downgrade(lua));
187+
self.weak.write(XRc::downgrade(lua));
188188
}
189189

190190
pub(super) unsafe fn get(state: *mut ffi::lua_State) -> *mut Self {
@@ -206,14 +206,14 @@ impl ExtraData {
206206
(*extra_ptr).get()
207207
}
208208

209-
unsafe fn store(extra: &Rc<UnsafeCell<Self>>, state: *mut ffi::lua_State) -> Result<()> {
209+
unsafe fn store(extra: &XRc<UnsafeCell<Self>>, state: *mut ffi::lua_State) -> Result<()> {
210210
#[cfg(feature = "luau")]
211211
if cfg!(not(feature = "module")) {
212212
(*ffi::lua_callbacks(state)).userdata = extra.get() as *mut _;
213213
return Ok(());
214214
}
215215

216-
push_gc_userdata(state, Rc::clone(extra), true)?;
216+
push_gc_userdata(state, XRc::clone(extra), true)?;
217217
protect_lua!(state, 1, 0, fn(state) {
218218
let extra_key = &EXTRA_REGISTRY_KEY as *const u8 as *const c_void;
219219
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, extra_key);

src/state/raw.rs

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ use std::result::Result as StdResult;
88
use std::sync::Arc;
99
use std::{mem, ptr};
1010

11-
use parking_lot::ReentrantMutex;
12-
1311
use crate::chunk::ChunkMode;
1412
use crate::error::{Error, Result};
1513
use crate::function::Function;
@@ -21,7 +19,7 @@ use crate::table::Table;
2119
use crate::thread::Thread;
2220
use crate::types::{
2321
AppDataRef, AppDataRefMut, Callback, CallbackUpvalue, DestructedUserdata, Integer,
24-
LightUserData, MaybeSend, RegistryKey, SubtypeId, ValueRef,
22+
LightUserData, MaybeSend, ReentrantMutex, RegistryKey, SubtypeId, ValueRef, XRc,
2523
};
2624
use crate::userdata::{AnyUserData, MetaMethod, UserData, UserDataRegistry, UserDataVariant};
2725
use crate::util::{
@@ -50,7 +48,7 @@ pub struct RawLua {
5048
// The state is dynamic and depends on context
5149
pub(super) state: Cell<*mut ffi::lua_State>,
5250
pub(super) main_state: *mut ffi::lua_State,
53-
pub(super) extra: Rc<UnsafeCell<ExtraData>>,
51+
pub(super) extra: XRc<UnsafeCell<ExtraData>>,
5452
}
5553

5654
#[cfg(not(feature = "module"))]
@@ -69,6 +67,9 @@ impl Drop for RawLua {
6967
}
7068
}
7169

70+
#[cfg(feature = "send")]
71+
unsafe impl Send for RawLua {}
72+
7273
impl RawLua {
7374
#[inline(always)]
7475
pub(crate) fn lua(&self) -> &Lua {
@@ -96,7 +97,7 @@ impl RawLua {
9697
unsafe { (*self.extra.get()).ref_thread }
9798
}
9899

99-
pub(super) unsafe fn new(libs: StdLib, options: LuaOptions) -> Arc<ReentrantMutex<Self>> {
100+
pub(super) unsafe fn new(libs: StdLib, options: LuaOptions) -> XRc<ReentrantMutex<Self>> {
100101
let mem_state: *mut MemoryState = Box::into_raw(Box::default());
101102
let mut state = ffi::lua_newstate(ALLOCATOR, mem_state as *mut c_void);
102103
// If state is null then switch to Lua internal allocator
@@ -154,7 +155,7 @@ impl RawLua {
154155
rawlua
155156
}
156157

157-
pub(super) unsafe fn init_from_ptr(state: *mut ffi::lua_State) -> Arc<ReentrantMutex<Self>> {
158+
pub(super) unsafe fn init_from_ptr(state: *mut ffi::lua_State) -> XRc<ReentrantMutex<Self>> {
158159
assert!(!state.is_null(), "Lua state is NULL");
159160
if let Some(lua) = Self::try_from_ptr(state) {
160161
return lua;
@@ -209,10 +210,10 @@ impl RawLua {
209210
assert_stack(main_state, ffi::LUA_MINSTACK);
210211

211212
#[allow(clippy::arc_with_non_send_sync)]
212-
let rawlua = Arc::new(ReentrantMutex::new(RawLua {
213+
let rawlua = XRc::new(ReentrantMutex::new(RawLua {
213214
state: Cell::new(state),
214215
main_state,
215-
extra: Rc::clone(&extra),
216+
extra: XRc::clone(&extra),
216217
}));
217218
(*extra.get()).set_lua(&rawlua);
218219

@@ -221,10 +222,10 @@ impl RawLua {
221222

222223
pub(super) unsafe fn try_from_ptr(
223224
state: *mut ffi::lua_State,
224-
) -> Option<Arc<ReentrantMutex<Self>>> {
225+
) -> Option<XRc<ReentrantMutex<Self>>> {
225226
match ExtraData::get(state) {
226227
extra if extra.is_null() => None,
227-
extra => Some(Arc::clone(&(*extra).lua().0)),
228+
extra => Some(XRc::clone(&(*extra).lua().0)),
228229
}
229230
}
230231

@@ -369,7 +370,7 @@ impl RawLua {
369370
callback_error_ext(state, extra, move |_| {
370371
let hook_cb = (*extra).hook_callback.clone();
371372
let hook_cb = mlua_expect!(hook_cb, "no hook callback set in hook_proc");
372-
if Arc::strong_count(&hook_cb) > 2 {
373+
if Rc::strong_count(&hook_cb) > 2 {
373374
return Ok(()); // Don't allow recursion
374375
}
375376
let rawlua = (*extra).raw_lua();
@@ -379,7 +380,7 @@ impl RawLua {
379380
})
380381
}
381382

382-
(*self.extra.get()).hook_callback = Some(Arc::new(callback));
383+
(*self.extra.get()).hook_callback = Some(Rc::new(callback));
383384
(*self.extra.get()).hook_thread = state; // Mark for what thread the hook is set
384385
ffi::lua_sethook(state, Some(hook_proc), triggers.mask(), triggers.count());
385386
}
@@ -1105,7 +1106,7 @@ impl RawLua {
11051106
check_stack(state, 4)?;
11061107

11071108
let func = mem::transmute::<Callback, Callback<'static>>(func);
1108-
let extra = Rc::clone(&self.extra);
1109+
let extra = XRc::clone(&self.extra);
11091110
let protect = !self.unlikely_memory_error();
11101111
push_gc_userdata(state, CallbackUpvalue { data: func, extra }, protect)?;
11111112
if protect {
@@ -1149,7 +1150,7 @@ impl RawLua {
11491150
let args = MultiValue::from_stack_multi(nargs, rawlua)?;
11501151
let func = &*(*upvalue).data;
11511152
let fut = func(rawlua, args);
1152-
let extra = Rc::clone(&(*upvalue).extra);
1153+
let extra = XRc::clone(&(*upvalue).extra);
11531154
let protect = !rawlua.unlikely_memory_error();
11541155
push_gc_userdata(state, AsyncPollUpvalue { data: fut, extra }, protect)?;
11551156
if protect {
@@ -1209,7 +1210,7 @@ impl RawLua {
12091210
check_stack(state, 4)?;
12101211

12111212
let func = mem::transmute::<AsyncCallback, AsyncCallback<'static>>(func);
1212-
let extra = Rc::clone(&self.extra);
1213+
let extra = XRc::clone(&self.extra);
12131214
let protect = !self.unlikely_memory_error();
12141215
let upvalue = AsyncCallbackUpvalue { data: func, extra };
12151216
push_gc_userdata(state, upvalue, protect)?;

0 commit comments

Comments
 (0)