Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions glib/src/thread_guard.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Take a look at the license at the top of the repository in the LICENSE file.

use std::{
mem, ptr,
mem::ManuallyDrop,
sync::atomic::{AtomicUsize, Ordering},
};
fn next_thread_id() -> usize {
Expand All @@ -23,7 +23,9 @@ pub fn thread_id() -> usize {
/// Thread guard that only gives access to the contained value on the thread it was created on.
pub struct ThreadGuard<T> {
thread_id: usize,
value: T,
// This is a `ManuallyDrop` so that the automatic drop glue does not drop `T`
// if this `ThreadGuard` is dropped on the wrong thread.
value: ManuallyDrop<T>,
}

impl<T> ThreadGuard<T> {
Expand All @@ -38,7 +40,7 @@ impl<T> ThreadGuard<T> {
pub fn new(value: T) -> Self {
Self {
thread_id: thread_id(),
value,
value: ManuallyDrop::new(value),
}
}

Expand Down Expand Up @@ -85,12 +87,16 @@ impl<T> ThreadGuard<T> {
/// created.
#[inline]
pub fn into_inner(self) -> T {
// We wrap `self` in `ManuallyDrop` to defuse `ThreadGuard`'s `Drop` impl.
let mut this = ManuallyDrop::new(self);

assert!(
self.thread_id == thread_id(),
this.thread_id == thread_id(),
"Value accessed from different thread than where it was created"
);

unsafe { ptr::read(&mem::ManuallyDrop::new(self).value) }
// SAFETY: We are on the right thread, and this.value will not be touched after this
unsafe { ManuallyDrop::take(&mut this.value) }
}

// rustdoc-stripper-ignore-next
Expand All @@ -108,6 +114,9 @@ impl<T> Drop for ThreadGuard<T> {
self.thread_id == thread_id(),
"Value dropped on a different thread than where it was created"
);

// SAFETY: We are on the right thread, and self.value will not be touched after this
unsafe { ManuallyDrop::drop(&mut self.value) }
}
}

Expand Down
Loading