diff --git a/src/userdata/cell.rs b/src/userdata/cell.rs index c327a86..1031369 100644 --- a/src/userdata/cell.rs +++ b/src/userdata/cell.rs @@ -27,7 +27,7 @@ type DynSerialize = dyn erased_serde::Serialize + Send; pub(crate) enum UserDataVariant { Default(XRc>), #[cfg(feature = "serialize")] - Serializable(XRc>>>), + Serializable(XRc>>), } impl Clone for UserDataVariant { @@ -82,7 +82,7 @@ impl UserDataVariant { Self::Default(inner) => XRc::into_inner(inner).unwrap().value.into_inner(), #[cfg(feature = "serialize")] Self::Serializable(inner) => unsafe { - let raw = Box::into_raw(XRc::into_inner(inner).unwrap().value.into_inner().0); + let raw = Box::into_raw(XRc::into_inner(inner).unwrap().value.into_inner()); *Box::from_raw(raw as *mut T) }, }) @@ -112,7 +112,6 @@ impl UserDataVariant { #[inline(always)] pub(crate) fn new_ser(data: T) -> Self { let data = Box::new(data) as Box; - let data = ForceSync(data); Self::Serializable(XRc::new(UserDataCell::new(data))) } } @@ -129,7 +128,7 @@ impl Serialize for UserDataVariant<()> { // No need to do this if the `send` feature is disabled. #[cfg(not(feature = "send"))] let _guard = self.try_borrow().map_err(serde::ser::Error::custom)?; - (*inner.value.get()).0.serialize(serializer) + (*inner.value.get()).serialize(serializer) }, } } @@ -142,7 +141,7 @@ pub(crate) struct UserDataCell { } unsafe impl Send for UserDataCell {} -unsafe impl Sync for UserDataCell {} +unsafe impl Sync for UserDataCell {} impl UserDataCell { #[inline(always)] @@ -352,11 +351,6 @@ impl<'a, T> TryFrom<&'a UserDataVariant> for UserDataBorrowMut<'a, T> { } } -#[repr(transparent)] -pub(crate) struct ForceSync(T); - -unsafe impl Sync for ForceSync {} - #[inline] fn try_value_to_userdata(value: Value) -> Result { match value { diff --git a/src/userdata/lock.rs b/src/userdata/lock.rs index 7ddf6be..8845f33 100644 --- a/src/userdata/lock.rs +++ b/src/userdata/lock.rs @@ -62,32 +62,32 @@ mod lock_impl { #[cfg(feature = "send")] mod lock_impl { - use parking_lot::lock_api::RawRwLock; + use parking_lot::lock_api::RawMutex; - pub(crate) type RawLock = parking_lot::RawRwLock; + pub(crate) type RawLock = parking_lot::RawMutex; impl super::UserDataLock for RawLock { #[allow(clippy::declare_interior_mutable_const)] - const INIT: Self = ::INIT; + const INIT: Self = ::INIT; #[inline(always)] fn try_lock_shared(&self) -> bool { - RawRwLock::try_lock_shared(self) + RawLock::try_lock(self) } #[inline(always)] fn try_lock_exclusive(&self) -> bool { - RawRwLock::try_lock_exclusive(self) + RawLock::try_lock(self) } #[inline(always)] unsafe fn unlock_shared(&self) { - RawRwLock::unlock_shared(self) + RawLock::unlock(self) } #[inline(always)] unsafe fn unlock_exclusive(&self) { - RawRwLock::unlock_exclusive(self) + RawLock::unlock(self) } } } diff --git a/tests/send.rs b/tests/send.rs new file mode 100644 index 0000000..25b0602 --- /dev/null +++ b/tests/send.rs @@ -0,0 +1,35 @@ +#![cfg(feature = "send")] + +use std::cell::UnsafeCell; +use std::marker::PhantomData; +use std::string::String as StdString; + +use mlua::{AnyUserData, Error, Lua, Result, UserDataRef}; +use static_assertions::{assert_impl_all, assert_not_impl_all}; + +#[test] +fn test_userdata_multithread_access() -> Result<()> { + let lua = Lua::new(); + + // This type is `Send` but not `Sync`. + struct MyUserData(#[allow(unused)] StdString, PhantomData>); + + assert_impl_all!(MyUserData: Send); + assert_not_impl_all!(MyUserData: Sync); + + lua.globals().set( + "ud", + AnyUserData::wrap(MyUserData("hello".to_string(), PhantomData)), + )?; + // We acquired the exclusive reference. + let _ud1 = lua.globals().get::>("ud")?; + + std::thread::scope(|s| { + s.spawn(|| { + let res = lua.globals().get::>("ud"); + assert!(matches!(res, Err(Error::UserDataBorrowError))); + }); + }); + + Ok(()) +}