Skip to content

Commit 1de5826

Browse files
authored
feat(zts): set lock per thread on zts build (#408)
1 parent 828338d commit 1de5826

File tree

2 files changed

+111
-20
lines changed

2 files changed

+111
-20
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ exclude = ["/.github", "/.crates"]
1313

1414
[dependencies]
1515
bitflags = "2"
16-
parking_lot = "0.12"
16+
parking_lot = { version = "0.12", features = ["arc_lock"] }
1717
cfg-if = "1.0"
1818
once_cell = "1.17"
1919
anyhow = { version = "1", optional = true }

src/zend/globals.rs

Lines changed: 110 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
//! Types related to the PHP executor, sapi and process globals.
22
3+
use parking_lot::{ArcRwLockReadGuard, ArcRwLockWriteGuard, RawRwLock, RwLock};
34
use std::collections::HashMap;
45
use std::ffi::CStr;
56
use std::ops::{Deref, DerefMut};
67
use std::slice;
78
use std::str;
8-
9-
use parking_lot::{const_rwlock, RwLock, RwLockReadGuard, RwLockWriteGuard};
9+
use std::sync::{Arc, LazyLock};
1010

1111
use crate::boxed::ZBox;
1212
use crate::exception::PhpResult;
@@ -51,7 +51,15 @@ impl ExecutorGlobals {
5151
// return an invalid pointer.
5252
let globals = unsafe { ext_php_rs_executor_globals().as_ref() }
5353
.expect("Static executor globals were invalid");
54-
let guard = GLOBALS_LOCK.read();
54+
55+
cfg_if::cfg_if! {
56+
if #[cfg(php_zts)] {
57+
let guard = lock::GLOBALS_LOCK.with(|l| l.read_arc());
58+
} else {
59+
let guard = lock::GLOBALS_LOCK.read_arc();
60+
}
61+
}
62+
5563
GlobalReadGuard { globals, guard }
5664
}
5765

@@ -67,7 +75,15 @@ impl ExecutorGlobals {
6775
// return an invalid pointer.
6876
let globals = unsafe { ext_php_rs_executor_globals().as_mut() }
6977
.expect("Static executor globals were invalid");
70-
let guard = GLOBALS_LOCK.write();
78+
79+
cfg_if::cfg_if! {
80+
if #[cfg(php_zts)] {
81+
let guard = lock::GLOBALS_LOCK.with(|l| l.write_arc());
82+
} else {
83+
let guard = lock::GLOBALS_LOCK.write_arc();
84+
}
85+
}
86+
7187
GlobalWriteGuard { globals, guard }
7288
}
7389

@@ -198,7 +214,7 @@ impl SapiModule {
198214
// return an invalid pointer.
199215
let globals = unsafe { ext_php_rs_sapi_module().as_ref() }
200216
.expect("Static executor globals were invalid");
201-
let guard = SAPI_MODULE_LOCK.read();
217+
let guard = SAPI_MODULE_LOCK.read_arc();
202218
GlobalReadGuard { globals, guard }
203219
}
204220

@@ -214,7 +230,7 @@ impl SapiModule {
214230
// return an invalid pointer.
215231
let globals = unsafe { ext_php_rs_sapi_module().as_mut() }
216232
.expect("Static executor globals were invalid");
217-
let guard = SAPI_MODULE_LOCK.write();
233+
let guard = SAPI_MODULE_LOCK.write_arc();
218234
GlobalWriteGuard { globals, guard }
219235
}
220236
}
@@ -234,7 +250,15 @@ impl ProcessGlobals {
234250
// SAFETY: PHP executor globals are statically declared therefore should never
235251
// return an invalid pointer.
236252
let globals = unsafe { &*ext_php_rs_process_globals() };
237-
let guard = PROCESS_GLOBALS_LOCK.read();
253+
254+
cfg_if::cfg_if! {
255+
if #[cfg(php_zts)] {
256+
let guard = lock::PROCESS_GLOBALS_LOCK.with(|l| l.read_arc());
257+
} else {
258+
let guard = lock::PROCESS_GLOBALS_LOCK.read_arc();
259+
}
260+
}
261+
238262
GlobalReadGuard { globals, guard }
239263
}
240264

@@ -249,7 +273,15 @@ impl ProcessGlobals {
249273
// SAFETY: PHP executor globals are statically declared therefore should never
250274
// return an invalid pointer.
251275
let globals = unsafe { &mut *ext_php_rs_process_globals() };
252-
let guard = PROCESS_GLOBALS_LOCK.write();
276+
277+
cfg_if::cfg_if! {
278+
if #[cfg(php_zts)] {
279+
let guard = lock::PROCESS_GLOBALS_LOCK.with(|l| l.write_arc());
280+
} else {
281+
let guard = lock::PROCESS_GLOBALS_LOCK.write_arc();
282+
}
283+
}
284+
253285
GlobalWriteGuard { globals, guard }
254286
}
255287

@@ -357,7 +389,15 @@ impl SapiGlobals {
357389
// SAFETY: PHP executor globals are statically declared therefore should never
358390
// return an invalid pointer.
359391
let globals = unsafe { &*ext_php_rs_sapi_globals() };
360-
let guard = SAPI_GLOBALS_LOCK.read();
392+
393+
cfg_if::cfg_if! {
394+
if #[cfg(php_zts)] {
395+
let guard = lock::SAPI_GLOBALS_LOCK.with(|l| l.read_arc());
396+
} else {
397+
let guard = lock::SAPI_GLOBALS_LOCK.read_arc();
398+
}
399+
}
400+
361401
GlobalReadGuard { globals, guard }
362402
}
363403

@@ -372,7 +412,15 @@ impl SapiGlobals {
372412
// SAFETY: PHP executor globals are statically declared therefore should never
373413
// return an invalid pointer.
374414
let globals = unsafe { &mut *ext_php_rs_sapi_globals() };
375-
let guard = SAPI_GLOBALS_LOCK.write();
415+
416+
cfg_if::cfg_if! {
417+
if #[cfg(php_zts)] {
418+
let guard = lock::SAPI_GLOBALS_LOCK.with(|l| l.write_arc());
419+
} else {
420+
let guard = lock::SAPI_GLOBALS_LOCK.write_arc();
421+
}
422+
}
423+
376424
GlobalWriteGuard { globals, guard }
377425
}
378426

@@ -576,7 +624,15 @@ impl FileGlobals {
576624
// return an invalid pointer.
577625
let globals = unsafe { ext_php_rs_file_globals().as_ref() }
578626
.expect("Static file globals were invalid");
579-
let guard = FILE_GLOBALS_LOCK.read();
627+
628+
cfg_if::cfg_if! {
629+
if #[cfg(php_zts)] {
630+
let guard = lock::FILE_GLOBALS_LOCK.with(|l| l.read_arc());
631+
} else {
632+
let guard = lock::FILE_GLOBALS_LOCK.read_arc();
633+
}
634+
}
635+
580636
GlobalReadGuard { globals, guard }
581637
}
582638

@@ -591,7 +647,15 @@ impl FileGlobals {
591647
// SAFETY: PHP executor globals are statically declared therefore should never
592648
// return an invalid pointer.
593649
let globals = unsafe { &mut *ext_php_rs_file_globals() };
594-
let guard = SAPI_GLOBALS_LOCK.write();
650+
651+
cfg_if::cfg_if! {
652+
if #[cfg(php_zts)] {
653+
let guard = lock::FILE_GLOBALS_LOCK.with(|l| l.write_arc());
654+
} else {
655+
let guard = lock::FILE_GLOBALS_LOCK.write_arc();
656+
}
657+
}
658+
595659
GlobalWriteGuard { globals, guard }
596660
}
597661

@@ -605,23 +669,50 @@ impl FileGlobals {
605669
///
606670
/// PHP provides no indication if the executor globals are being accessed so
607671
/// this is only effective on the Rust side.
608-
static GLOBALS_LOCK: RwLock<()> = const_rwlock(());
609-
static PROCESS_GLOBALS_LOCK: RwLock<()> = const_rwlock(());
610-
static SAPI_GLOBALS_LOCK: RwLock<()> = const_rwlock(());
611-
static FILE_GLOBALS_LOCK: RwLock<()> = const_rwlock(());
672+
#[cfg(not(php_zts))]
673+
pub(crate) mod lock {
674+
use parking_lot::RwLock;
675+
use std::sync::{Arc, LazyLock};
676+
677+
pub(crate) static GLOBALS_LOCK: LazyLock<Arc<RwLock<()>>> =
678+
LazyLock::new(|| Arc::new(RwLock::new(())));
679+
pub(crate) static PROCESS_GLOBALS_LOCK: LazyLock<Arc<RwLock<()>>> =
680+
LazyLock::new(|| Arc::new(RwLock::new(())));
681+
pub(crate) static SAPI_GLOBALS_LOCK: LazyLock<Arc<RwLock<()>>> =
682+
LazyLock::new(|| Arc::new(RwLock::new(())));
683+
pub(crate) static FILE_GLOBALS_LOCK: LazyLock<Arc<RwLock<()>>> =
684+
LazyLock::new(|| Arc::new(RwLock::new(())));
685+
}
686+
687+
/// Executor globals rwlock.
688+
///
689+
/// PHP provides no indication if the executor globals are being accessed so
690+
/// this is only effective on the Rust side.
691+
#[cfg(php_zts)]
692+
pub(crate) mod lock {
693+
use parking_lot::{const_rwlock, RwLock};
694+
use std::sync::Arc;
695+
696+
thread_local! {
697+
pub(crate) static GLOBALS_LOCK: Arc<RwLock<()>> = Arc::new(const_rwlock(()));
698+
pub(crate) static PROCESS_GLOBALS_LOCK: Arc<RwLock<()>> = Arc::new( const_rwlock(()) );
699+
pub(crate) static SAPI_GLOBALS_LOCK: Arc<RwLock<()>> = Arc::new( const_rwlock(()) );
700+
pub(crate) static FILE_GLOBALS_LOCK: Arc<RwLock<()>> = Arc::new( const_rwlock(()) );
701+
}
702+
}
612703

613704
/// SAPI globals rwlock.
614705
///
615706
/// PHP provides no indication if the executor globals are being accessed so
616707
/// this is only effective on the Rust side.
617-
static SAPI_MODULE_LOCK: RwLock<()> = const_rwlock(());
708+
static SAPI_MODULE_LOCK: LazyLock<Arc<RwLock<()>>> = LazyLock::new(|| Arc::new(RwLock::new(())));
618709

619710
/// Wrapper guard that contains a reference to a given type `T`. Dropping a
620711
/// guard releases the lock on the relevant rwlock.
621712
pub struct GlobalReadGuard<T: 'static> {
622713
globals: &'static T,
623714
#[allow(dead_code)]
624-
guard: RwLockReadGuard<'static, ()>,
715+
guard: ArcRwLockReadGuard<RawRwLock, ()>,
625716
}
626717

627718
impl<T> Deref for GlobalReadGuard<T> {
@@ -637,7 +728,7 @@ impl<T> Deref for GlobalReadGuard<T> {
637728
pub struct GlobalWriteGuard<T: 'static> {
638729
globals: &'static mut T,
639730
#[allow(dead_code)]
640-
guard: RwLockWriteGuard<'static, ()>,
731+
guard: ArcRwLockWriteGuard<RawRwLock, ()>,
641732
}
642733

643734
impl<T> Deref for GlobalWriteGuard<T> {

0 commit comments

Comments
 (0)