Skip to content

Commit cdf14ab

Browse files
committed
Fix reference counting in DispatchSemaphoreGuard::release
1 parent 09f6049 commit cdf14ab

File tree

1 file changed

+42
-10
lines changed

1 file changed

+42
-10
lines changed

crates/dispatch2/src/semaphore.rs

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use core::mem::ManuallyDrop;
2-
31
use crate::{DispatchObject, DispatchRetained};
42

53
use crate::{DispatchTime, WaitError};
@@ -37,20 +35,54 @@ impl DispatchSemaphore {
3735
pub struct DispatchSemaphoreGuard(DispatchRetained<DispatchSemaphore>);
3836

3937
impl DispatchSemaphoreGuard {
40-
/// Release the [`DispatchSemaphore`].
41-
pub fn release(self) -> bool {
42-
let this = ManuallyDrop::new(self);
43-
38+
/// Signal the associated [`DispatchSemaphore`].
39+
///
40+
/// This is an internal helper, called by wrappers that ensure it is called exactly
41+
/// once, immediately prior to dropping the guard.
42+
fn signal(&self) -> bool {
4443
// SAFETY: DispatchSemaphore cannot be null.
45-
let result = this.0.signal();
44+
self.0.signal() != 0
45+
}
4646

47-
result != 0
47+
/// Release the [`DispatchSemaphore`].
48+
pub fn release(self) -> bool {
49+
self.signal()
4850
}
4951
}
5052

5153
impl Drop for DispatchSemaphoreGuard {
5254
fn drop(&mut self) {
53-
// SAFETY: DispatchSemaphore cannot be null.
54-
self.0.signal();
55+
self.signal();
56+
}
57+
}
58+
59+
#[cfg(test)]
60+
mod tests {
61+
use super::*;
62+
63+
#[test]
64+
#[cfg(feature = "objc2")]
65+
#[cfg_attr(not(target_vendor = "apple"), ignore = "only Apple's libdisptch is interoperable with `objc2`")]
66+
fn acquire_release() {
67+
fn retain_count(semaphore: &DispatchSemaphore) -> usize {
68+
// SAFETY: semaphore is valid and the method signature is correct.
69+
unsafe { objc2::msg_send![semaphore, retainCount] }
70+
}
71+
72+
let semaphore = DispatchSemaphore::new(1);
73+
74+
assert_eq!(retain_count(&semaphore), 1);
75+
{
76+
let _guard = semaphore.try_acquire(DispatchTime::NOW).unwrap();
77+
assert_eq!(retain_count(&semaphore), 2);
78+
}
79+
assert_eq!(retain_count(&semaphore), 1);
80+
{
81+
let guard = semaphore.try_acquire(DispatchTime::NOW).unwrap();
82+
assert_eq!(retain_count(&semaphore), 2);
83+
guard.release();
84+
assert_eq!(retain_count(&semaphore), 1);
85+
}
86+
assert_eq!(retain_count(&semaphore), 1);
5587
}
5688
}

0 commit comments

Comments
 (0)