Skip to content

Commit 18ed26c

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

File tree

1 file changed

+46
-10
lines changed

1 file changed

+46
-10
lines changed

crates/dispatch2/src/semaphore.rs

Lines changed: 46 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,58 @@ 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+
#[allow(unused_imports)]
62+
use super::*;
63+
64+
#[test]
65+
#[cfg(feature = "objc2")]
66+
#[cfg_attr(
67+
not(target_vendor = "apple"),
68+
ignore = "only Apple's libdisptch is interoperable with `objc2`"
69+
)]
70+
fn acquire_release() {
71+
fn retain_count(semaphore: &DispatchSemaphore) -> usize {
72+
// SAFETY: semaphore is valid and the method signature is correct.
73+
unsafe { objc2::msg_send![semaphore, retainCount] }
74+
}
75+
76+
let semaphore = DispatchSemaphore::new(1);
77+
78+
assert_eq!(retain_count(&semaphore), 1);
79+
{
80+
let _guard = semaphore.try_acquire(DispatchTime::NOW).unwrap();
81+
assert_eq!(retain_count(&semaphore), 2);
82+
}
83+
assert_eq!(retain_count(&semaphore), 1);
84+
{
85+
let guard = semaphore.try_acquire(DispatchTime::NOW).unwrap();
86+
assert_eq!(retain_count(&semaphore), 2);
87+
guard.release();
88+
assert_eq!(retain_count(&semaphore), 1);
89+
}
90+
assert_eq!(retain_count(&semaphore), 1);
5591
}
5692
}

0 commit comments

Comments
 (0)