Skip to content

Commit 411c3a1

Browse files
committed
RLock: use single parking_lot level, track recursion manually
Instead of calling lock()/unlock() N times for recursion depth N, keep parking_lot at 1 level and manage the count ourselves. This makes acquire/release O(1) and matches CPython's _PyRecursiveMutex approach (lock once + set level directly).
1 parent de01099 commit 411c3a1

File tree

1 file changed

+16
-14
lines changed

1 file changed

+16
-14
lines changed

crates/vm/src/stdlib/thread.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -221,10 +221,16 @@ pub(crate) mod _thread {
221221
#[pymethod(name = "acquire_lock")]
222222
#[pymethod(name = "__enter__")]
223223
fn acquire(&self, args: AcquireArgs, vm: &VirtualMachine) -> PyResult<bool> {
224-
let result = acquire_lock_impl!(&self.mu, args, vm)?;
225-
if result {
224+
if self.mu.is_owned_by_current_thread() {
225+
// Re-entrant acquisition: just increment our count.
226+
// parking_lot stays at 1 level; we track recursion ourselves.
226227
self.count
227228
.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
229+
return Ok(true);
230+
}
231+
let result = acquire_lock_impl!(&self.mu, args, vm)?;
232+
if result {
233+
self.count.store(1, core::sync::atomic::Ordering::Relaxed);
228234
}
229235
Ok(result)
230236
}
@@ -234,13 +240,13 @@ pub(crate) mod _thread {
234240
if !self.mu.is_owned_by_current_thread() {
235241
return Err(vm.new_runtime_error("cannot release un-acquired lock"));
236242
}
237-
debug_assert!(
238-
self.count.load(core::sync::atomic::Ordering::Relaxed) > 0,
239-
"RLock count underflow"
240-
);
241-
self.count
243+
let prev = self
244+
.count
242245
.fetch_sub(1, core::sync::atomic::Ordering::Relaxed);
243-
unsafe { self.mu.unlock() };
246+
debug_assert!(prev > 0, "RLock count underflow");
247+
if prev == 1 {
248+
unsafe { self.mu.unlock() };
249+
}
244250
Ok(())
245251
}
246252

@@ -285,9 +291,7 @@ pub(crate) mod _thread {
285291
}
286292
let count = self.count.swap(0, core::sync::atomic::Ordering::Relaxed);
287293
debug_assert!(count > 0, "RLock count underflow");
288-
for _ in 0..count {
289-
unsafe { self.mu.unlock() };
290-
}
294+
unsafe { self.mu.unlock() };
291295
Ok((count, current_thread_id()))
292296
}
293297

@@ -303,9 +307,7 @@ pub(crate) mod _thread {
303307
if count == 0 {
304308
return Ok(());
305309
}
306-
for _ in 0..count {
307-
self.mu.lock();
308-
}
310+
self.mu.lock();
309311
self.count
310312
.store(count, core::sync::atomic::Ordering::Relaxed);
311313
Ok(())

0 commit comments

Comments
 (0)