Skip to content

Commit e249767

Browse files
committed
pw: loop: Make enter() and leave() unsafe and have iterate automatically call them.
Not calling those functions before `iterate` may be unsound, for example pw_thread_loop does locking/unlocking in those functions. This may still be done manually with unsafe, `enter()`, `leave()` and `iterate_unguarded()`.
1 parent 93979f6 commit e249767

File tree

1 file changed

+47
-37
lines changed

1 file changed

+47
-37
lines changed

pipewire/src/loop_.rs

+47-37
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,8 @@ use crate::utils::assert_main_thread;
1212
/// A transparent wrapper around a raw [`pw_loop`](`pw_sys::pw_loop`).
1313
/// It is usually only seen in a reference (`&LoopRef`).
1414
///
15-
/// This type is similar to rusts [`str`] type,
16-
/// where [`&str`](`std::str`) is a reference to a slice of characters,
17-
/// and [`&LoopRef`](`LoopRef`) is a reference to a [`pw_loop`](`pw_sys::pw_loop`).
18-
///
19-
/// Like with [`str`] and [`String`], an owned version, [`Loop`], is available,
20-
/// which can create of [`pw_loop`](`pw_sys::pw_loop`) and lets you own them,
15+
/// An owned version, [`Loop`], is available,
16+
/// which lets you create and own a [`pw_loop`](`pw_sys::pw_loop`),
2117
/// but other objects, such as [`MainLoop`](`crate::MainLoop`), also contain them.
2218
#[repr(transparent)]
2319
pub struct LoopRef(pw_sys::pw_loop);
@@ -49,32 +45,34 @@ impl LoopRef {
4945
/// Start an iteration of the loop. This function should be called
5046
/// before calling iterate and is typically used to capture the thread
5147
/// that this loop will run in.
52-
pub fn enter(&self) {
53-
unsafe {
54-
let mut iface = self.as_raw().control.as_ref().unwrap().iface;
48+
///
49+
/// # Safety
50+
/// Each call of `enter` must be paired with a call of `leave`.
51+
pub unsafe fn enter(&self) {
52+
let mut iface = self.as_raw().control.as_ref().unwrap().iface;
5553

56-
spa_interface_call_method!(
57-
&mut iface as *mut spa_sys::spa_interface,
58-
spa_sys::spa_loop_control_methods,
59-
enter,
60-
)
61-
}
54+
spa_interface_call_method!(
55+
&mut iface as *mut spa_sys::spa_interface,
56+
spa_sys::spa_loop_control_methods,
57+
enter,
58+
)
6259
}
6360

6461
/// Leave a loop
6562
///
6663
/// Ends the iteration of a loop. This should be called after calling
6764
/// iterate.
68-
pub fn leave(&self) {
69-
unsafe {
70-
let mut iface = self.as_raw().control.as_ref().unwrap().iface;
65+
///
66+
/// # Safety
67+
/// Each call of `leave` must be paired with a call of `enter`.
68+
pub unsafe fn leave(&self) {
69+
let mut iface = self.as_raw().control.as_ref().unwrap().iface;
7170

72-
spa_interface_call_method!(
73-
&mut iface as *mut spa_sys::spa_interface,
74-
spa_sys::spa_loop_control_methods,
75-
leave,
76-
)
77-
}
71+
spa_interface_call_method!(
72+
&mut iface as *mut spa_sys::spa_interface,
73+
spa_sys::spa_loop_control_methods,
74+
leave,
75+
)
7876
}
7977

8078
/// Perform one iteration of the loop.
@@ -86,29 +84,41 @@ impl LoopRef {
8684
/// up to the provided timeout and then dispatch the fds with activity.
8785
/// The number of dispatched fds is returned.
8886
///
89-
/// Before calling this, you should call [`Self::enter()`] on the loop, and [`Self::leave()`] afterwards.
87+
/// This will automatically call [`Self::enter()`] on the loop before iterating, and [`Self::leave()`] afterwards.
9088
///
9189
/// # Panics
9290
/// This function will panic if the provided timeout as milliseconds does not fit inside a
9391
/// `c_int` integer.
9492
pub fn iterate(&self, timeout: std::time::Duration) -> i32 {
9593
unsafe {
96-
let mut iface = self.as_raw().control.as_ref().unwrap().iface;
97-
98-
let timeout: c_int = timeout
99-
.as_millis()
100-
.try_into()
101-
.expect("Provided timeout does not fit in a c_int");
94+
self.enter();
95+
let res = self.iterate_unguarded(timeout);
96+
self.leave();
10297

103-
spa_interface_call_method!(
104-
&mut iface as *mut spa_sys::spa_interface,
105-
spa_sys::spa_loop_control_methods,
106-
iterate,
107-
timeout
108-
)
98+
res
10999
}
110100
}
111101

102+
/// A variant of [`iterate()`](`Self::iterate()`) that does not call [`Self::enter()`] and [`Self::leave()`] on the loop.
103+
///
104+
/// # Safety
105+
/// Before calling this, [`Self::enter()`] must be called, and [`Self::leave()`] must be called afterwards.
106+
pub unsafe fn iterate_unguarded(&self, timeout: std::time::Duration) -> i32 {
107+
let mut iface = self.as_raw().control.as_ref().unwrap().iface;
108+
109+
let timeout: c_int = timeout
110+
.as_millis()
111+
.try_into()
112+
.expect("Provided timeout does not fit in a c_int");
113+
114+
spa_interface_call_method!(
115+
&mut iface as *mut spa_sys::spa_interface,
116+
spa_sys::spa_loop_control_methods,
117+
iterate,
118+
timeout
119+
)
120+
}
121+
112122
/// Register some type of IO object with a callback that is called when reading/writing on the IO object
113123
/// is available.
114124
///

0 commit comments

Comments
 (0)