Skip to content

Commit 93f697c

Browse files
committed
Use a git version for RawReentrantMutex + RawMutexStatus
1 parent e110f5e commit 93f697c

File tree

3 files changed

+75
-140
lines changed

3 files changed

+75
-140
lines changed

Cargo.lock

Lines changed: 11 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vm/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ smallbox = "0.8"
7171
bstr = "0.2.12"
7272
crossbeam-utils = "0.7"
7373
generational-arena = "0.2"
74-
parking_lot = "0.10"
74+
parking_lot = { git = "https://github.com/Amanieu/parking_lot" }
7575

7676
## unicode stuff
7777
unicode_names2 = "0.4"

vm/src/stdlib/thread.rs

Lines changed: 63 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@ use crate::pyobject::{PyClassImpl, PyObjectRef, PyRef, PyResult, PyValue};
55
use crate::vm::VirtualMachine;
66

77
use parking_lot::{
8-
lock_api::{GetThreadId, RawMutex as RawMutexT, RawMutexTimed},
8+
lock_api::{RawMutex as RawMutexT, RawMutexTimed, RawReentrantMutex},
99
RawMutex, RawThreadId,
1010
};
11-
use std::cell::Cell;
1211
use std::fmt;
13-
use std::sync::atomic::{AtomicUsize, Ordering};
1412
use std::time::Duration;
1513

1614
#[cfg(not(target_os = "windows"))]
@@ -21,44 +19,6 @@ const PY_TIMEOUT_MAX: isize = 0xffffffff * 1_000_000;
2119

2220
const TIMEOUT_MAX: f64 = (PY_TIMEOUT_MAX / 1_000_000_000) as f64;
2321

24-
#[pyimpl]
25-
trait LockProtocol: PyValue {
26-
type RawMutex: RawMutexT + RawMutexTimed<Duration = Duration>;
27-
fn mutex(&self) -> &Self::RawMutex;
28-
29-
#[pymethod]
30-
#[pymethod(name = "acquire_lock")]
31-
#[pymethod(name = "__enter__")]
32-
#[allow(clippy::float_cmp, clippy::match_bool)]
33-
fn acquire(&self, args: AcquireArgs, vm: &VirtualMachine) -> PyResult<bool> {
34-
let mu = self.mutex();
35-
match args.waitflag {
36-
true if args.timeout == -1.0 => {
37-
mu.lock();
38-
Ok(true)
39-
}
40-
true if args.timeout < 0.0 => {
41-
Err(vm.new_value_error("timeout value must be positive".to_owned()))
42-
}
43-
true => Ok(mu.try_lock_for(Duration::from_secs_f64(args.timeout))),
44-
false if args.timeout != -1.0 => {
45-
Err(vm
46-
.new_value_error("can't specify a timeout for a non-blocking call".to_owned()))
47-
}
48-
false => Ok(mu.try_lock()),
49-
}
50-
}
51-
#[pymethod]
52-
#[pymethod(name = "release_lock")]
53-
fn release(&self) {
54-
self.mutex().unlock()
55-
}
56-
57-
#[pymethod(magic)]
58-
fn exit(&self, _args: PyFuncArgs) {
59-
self.release()
60-
}
61-
}
6222
#[derive(FromArgs)]
6323
struct AcquireArgs {
6424
#[pyarg(positional_or_keyword, default = "true")]
@@ -84,98 +44,43 @@ impl fmt::Debug for PyLock {
8444
}
8545
}
8646

87-
impl LockProtocol for PyLock {
88-
type RawMutex = RawMutex;
89-
fn mutex(&self) -> &RawMutex {
90-
&self.mu
91-
}
92-
}
93-
94-
#[pyimpl(with(LockProtocol))]
47+
#[pyimpl]
9548
impl PyLock {
96-
// TODO: locked(), might require something to change in parking_lot
97-
}
98-
99-
// Copied from lock_api
100-
// TODO: open a PR to make this public in lock_api
101-
struct RawReentrantMutex<R, G> {
102-
owner: AtomicUsize,
103-
lock_count: Cell<usize>,
104-
mutex: R,
105-
get_thread_id: G,
106-
}
107-
108-
impl<R: RawMutexT, G: GetThreadId> RawReentrantMutex<R, G> {
109-
#[inline]
110-
fn lock_internal<F: FnOnce() -> bool>(&self, try_lock: F) -> bool {
111-
let id = self.get_thread_id.nonzero_thread_id().get();
112-
if self.owner.load(Ordering::Relaxed) == id {
113-
self.lock_count.set(
114-
self.lock_count
115-
.get()
116-
.checked_add(1)
117-
.expect("ReentrantMutex lock count overflow"),
118-
);
119-
} else {
120-
if !try_lock() {
121-
return false;
49+
#[pymethod]
50+
#[pymethod(name = "acquire_lock")]
51+
#[pymethod(name = "__enter__")]
52+
#[allow(clippy::float_cmp, clippy::match_bool)]
53+
fn acquire(&self, args: AcquireArgs, vm: &VirtualMachine) -> PyResult<bool> {
54+
match args.waitflag {
55+
true if args.timeout == -1.0 => {
56+
self.mu.lock();
57+
Ok(true)
58+
}
59+
true if args.timeout < 0.0 => {
60+
Err(vm.new_value_error("timeout value must be positive".to_owned()))
61+
}
62+
true => Ok(self.mu.try_lock_for(Duration::from_secs_f64(args.timeout))),
63+
false if args.timeout != -1.0 => {
64+
Err(vm
65+
.new_value_error("can't specify a timeout for a non-blocking call".to_owned()))
12266
}
123-
self.owner.store(id, Ordering::Relaxed);
124-
debug_assert_eq!(self.lock_count.get(), 0);
125-
self.lock_count.set(1);
67+
false => Ok(self.mu.try_lock()),
12668
}
127-
true
12869
}
129-
}
130-
131-
unsafe impl<R: RawMutexT + Send, G: GetThreadId + Send> Send for RawReentrantMutex<R, G> {}
132-
unsafe impl<R: RawMutexT + Sync, G: GetThreadId + Sync> Sync for RawReentrantMutex<R, G> {}
133-
134-
unsafe impl<R: RawMutexT, G: GetThreadId> RawMutexT for RawReentrantMutex<R, G> {
135-
const INIT: Self = RawReentrantMutex {
136-
owner: AtomicUsize::new(0),
137-
lock_count: Cell::new(0),
138-
mutex: R::INIT,
139-
get_thread_id: G::INIT,
140-
};
141-
142-
type GuardMarker = R::GuardMarker;
143-
144-
#[inline]
145-
fn lock(&self) {
146-
self.lock_internal(|| {
147-
self.mutex.lock();
148-
true
149-
});
150-
}
151-
152-
#[inline]
153-
fn try_lock(&self) -> bool {
154-
self.lock_internal(|| self.mutex.try_lock())
70+
#[pymethod]
71+
#[pymethod(name = "release_lock")]
72+
fn release(&self) {
73+
self.mu.unlock()
15574
}
15675

157-
#[inline]
158-
fn unlock(&self) {
159-
let lock_count = self.lock_count.get() - 1;
160-
self.lock_count.set(lock_count);
161-
if lock_count == 0 {
162-
self.owner.store(0, Ordering::Relaxed);
163-
self.mutex.unlock();
164-
}
165-
}
166-
}
167-
168-
unsafe impl<R: RawMutexTimed, G: GetThreadId> RawMutexTimed for RawReentrantMutex<R, G> {
169-
type Instant = R::Instant;
170-
type Duration = R::Duration;
171-
#[inline]
172-
fn try_lock_until(&self, timeout: R::Instant) -> bool {
173-
self.lock_internal(|| self.mutex.try_lock_until(timeout))
76+
#[pymethod(magic)]
77+
fn exit(&self, _args: PyFuncArgs) {
78+
self.release()
17479
}
17580

176-
#[inline]
177-
fn try_lock_for(&self, timeout: R::Duration) -> bool {
178-
self.lock_internal(|| self.mutex.try_lock_for(timeout))
81+
#[pymethod]
82+
fn locked(&self) -> bool {
83+
self.mu.is_locked()
17984
}
18085
}
18186

@@ -197,14 +102,7 @@ impl fmt::Debug for PyRLock {
197102
}
198103
}
199104

200-
impl LockProtocol for PyRLock {
201-
type RawMutex = RawRMutex;
202-
fn mutex(&self) -> &Self::RawMutex {
203-
&self.mu
204-
}
205-
}
206-
207-
#[pyimpl(with(LockProtocol))]
105+
#[pyimpl]
208106
impl PyRLock {
209107
#[pyslot]
210108
fn tp_new(cls: PyClassRef, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
@@ -213,6 +111,38 @@ impl PyRLock {
213111
}
214112
.into_ref_with_type(vm, cls)
215113
}
114+
115+
#[pymethod]
116+
#[pymethod(name = "acquire_lock")]
117+
#[pymethod(name = "__enter__")]
118+
#[allow(clippy::float_cmp, clippy::match_bool)]
119+
fn acquire(&self, args: AcquireArgs, vm: &VirtualMachine) -> PyResult<bool> {
120+
match args.waitflag {
121+
true if args.timeout == -1.0 => {
122+
self.mu.lock();
123+
Ok(true)
124+
}
125+
true if args.timeout < 0.0 => {
126+
Err(vm.new_value_error("timeout value must be positive".to_owned()))
127+
}
128+
true => Ok(self.mu.try_lock_for(Duration::from_secs_f64(args.timeout))),
129+
false if args.timeout != -1.0 => {
130+
Err(vm
131+
.new_value_error("can't specify a timeout for a non-blocking call".to_owned()))
132+
}
133+
false => Ok(self.mu.try_lock()),
134+
}
135+
}
136+
#[pymethod]
137+
#[pymethod(name = "release_lock")]
138+
fn release(&self) {
139+
self.mu.unlock()
140+
}
141+
142+
#[pymethod(magic)]
143+
fn exit(&self, _args: PyFuncArgs) {
144+
self.release()
145+
}
216146
}
217147

218148
fn get_ident() -> u64 {

0 commit comments

Comments
 (0)