Skip to content

Commit

Permalink
Merge pull request #331 from qwandor/threadsafety
Browse files Browse the repository at this point in the history
Make various types Send and Sync
  • Loading branch information
crumblingstatue authored Nov 21, 2024
2 parents 07b67ad + f47ccc9 commit 9377b69
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 0 deletions.
19 changes: 19 additions & 0 deletions src/audio/capture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,15 @@ pub struct SoundRecorderDriver<'a, R: 'a> {
recorder: &'a mut R,
}

// SAFETY: An `sfCustomSoundRecorder` isn't tied to a particular thread, so it can be sent between
// threads safely.
unsafe impl<R: Send> Send for SoundRecorderDriver<'_, R> {}

// SAFETY: An `&SoundRecorderDriver` only allows access to methods which read the status of the
// driver, which is fine to do from multiple threads at once. Thus it is safe to pass
// `&SoundRecorderDriver` between threads.
unsafe impl<R: Sync> Sync for SoundRecorderDriver<'_, R> {}

unsafe extern "C" fn on_start_callback<R: SoundRecorder>(user_data: *mut c_void) -> bool {
let recorder: *mut R = user_data.cast();
unsafe { (*recorder).on_start() }
Expand Down Expand Up @@ -246,6 +255,16 @@ pub struct SoundBufferRecorder {
handle: NonNull<ffi::sfSoundBufferRecorder>,
}

// SAFETY: An `sfSoundBufferRecorder` isn't tied to a particular thread, so it can be sent between
// threads safely.
unsafe impl Send for SoundBufferRecorder {}

// SAFETY: An `&SoundBufferRecorder` only allows access to methods which read the status of the
// recorder, which is fine to do from multiple threads at once. Thus it is safe to pass
// `&SoundBufferRecorder` between threads.
unsafe impl Sync for SoundBufferRecorder {}


impl SoundBufferRecorder {
/// Create a new sound buffer recorder
///
Expand Down
7 changes: 7 additions & 0 deletions src/audio/music.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ pub struct Music<'src> {
_stream: PhantomData<&'src mut ()>,
}

// SAFETY: An `sfMusic` isn't tied to a particular thread, so it can be sent between threads safely.
unsafe impl Send for Music<'_> {}

// SAFETY: An `&Music` only allows access to methods which read the status of the music, which is
// fine to do from multiple threads at once. Thus it is safe to pass `&Music` between threads.
unsafe impl Sync for Music<'_> {}

/// Creating and opening
impl<'src> Music<'src> {
/// Create a new (empty) `Music`.
Expand Down
7 changes: 7 additions & 0 deletions src/audio/sound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ pub struct Sound<'buf> {
buffer: PhantomData<&'buf SoundBuffer>,
}

// SAFETY: An `sfSound` isn't tied to a particular thread, so it can be sent between threads safely.
unsafe impl Send for Sound<'_> {}

// SAFETY: An `&Sound` only allows access to methods which read the status of the sound, which is
// fine to do from multiple threads at once. Thus it is safe to pass `&Sound` between threads.
unsafe impl Sync for Sound<'_> {}

/// Creation
impl<'buf> Sound<'buf> {
/// Create a new `Sound`
Expand Down
9 changes: 9 additions & 0 deletions src/cpp/fbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ impl<T: ?Sized> std::fmt::Debug for FBox<T> {
}
}

// SAFETY: An `FBox` owns its contents, so it is safe to move between threads if and only if the
// contents is safe to move between threads. This matches the behaviour of `std::boxed::Box`.
unsafe impl <T: Send> Send for FBox<T> {}

// SAFETY: An `FBox` derefs to its contents, so it is safe to pass an `&FBox<T>` between threads if
// and only if it is safe to pass a reference to its contents between threads. This matches the
// behaviour of `std::boxed::Box`.
unsafe impl <T: Sync> Sync for FBox<T> {}

impl<T: ?Sized> FBox<T> {
pub(crate) fn new(ptr: *mut T) -> Option<Self> {
NonNull::new(ptr).map(FBox)
Expand Down

0 comments on commit 9377b69

Please sign in to comment.