Skip to content

Commit

Permalink
ref: Use arc-swap
Browse files Browse the repository at this point in the history
  • Loading branch information
Swatinem committed Nov 24, 2022
1 parent 0f93bde commit a931084
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 46 deletions.
7 changes: 4 additions & 3 deletions sentry-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ harness = false

[features]
default = []
client = ["rand"]
client = ["rand", "arc-swap"]
# I would love to just have a `log` feature, but this is used inside a macro,
# and macros actually expand features (and extern crate) where they are used!
debug-logs = ["dep:log"]
Expand All @@ -41,10 +41,11 @@ sys-info = { version = "0.9.1", optional = true }
build_id = { version = "0.2.1", optional = true }
findshlibs = { version = "=0.10.2", optional = true }
rustc_version_runtime = { version = "0.2.1", optional = true }
indexmap = { version = "1.9.1", optional = true}
indexmap = { version = "1.9.1", optional = true }
arc-swap = { version = "1.5.1", optional = true }

[target.'cfg(target_family = "unix")'.dependencies]
pprof = { version = "0.11.0", optional = true, default-features = false}
pprof = { version = "0.11.0", optional = true, default-features = false }
libc = { version = "^0.2.66", optional = true }

[dev-dependencies]
Expand Down
74 changes: 31 additions & 43 deletions sentry-core/src/hub_impl.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use std::cell::{Cell, UnsafeCell};
use std::cell::Cell;
use std::sync::{Arc, PoisonError, RwLock};
use std::thread;

use crate::Scope;
use crate::{scope::Stack, Client, Hub};

use arc_swap::ArcSwap;
use once_cell::sync::Lazy;

static PROCESS_HUB: Lazy<(Arc<Hub>, thread::ThreadId)> = Lazy::new(|| {
Expand All @@ -15,9 +16,10 @@ static PROCESS_HUB: Lazy<(Arc<Hub>, thread::ThreadId)> = Lazy::new(|| {
});

thread_local! {
static THREAD_HUB: UnsafeCell<Arc<Hub>> = UnsafeCell::new(
Arc::new(Hub::new_from_top(&PROCESS_HUB.0)));
static USE_PROCESS_HUB: Cell<bool> = Cell::new(PROCESS_HUB.1 == thread::current().id());
static THREAD_HUB: (ArcSwap<Hub>, Cell<bool>) = (
ArcSwap::from_pointee(Hub::new_from_top(&PROCESS_HUB.0)),
Cell::new(PROCESS_HUB.1 == thread::current().id())
);
}

pub(crate) struct SwitchGuard {
Expand All @@ -26,39 +28,29 @@ pub(crate) struct SwitchGuard {

impl SwitchGuard {
pub(crate) fn new(hub: Arc<Hub>) -> Self {
let inner = THREAD_HUB.with(|ctx| unsafe {
let ptr = ctx.get();
if std::ptr::eq(&**ptr, &*hub) {
None
} else {
let was_process_hub = USE_PROCESS_HUB.with(|x| {
if x.get() {
x.set(false);
true
} else {
false
}
});
let old = (*ptr).clone();
*ptr = hub;
Some((old, was_process_hub))
let inner = THREAD_HUB.with(|(old_hub, is_process_hub)| {
{
let old_hub = old_hub.load();
if std::ptr::eq(old_hub.as_ref(), hub.as_ref()) {
return None;
}
}
let old_hub = old_hub.swap(hub);
let was_process_hub = is_process_hub.replace(false);
Some((old_hub, was_process_hub))
});
SwitchGuard { inner }
}

fn switch_internal(&mut self) -> Option<Arc<Hub>> {
fn swap(&mut self) -> Option<Arc<Hub>> {
if let Some((old_hub, was_process_hub)) = self.inner.take() {
let current_hub = THREAD_HUB.with(|ctx| unsafe {
let ptr = ctx.get();
let current_hub = (*ptr).clone();
*ptr = old_hub;
current_hub
});
if was_process_hub {
USE_PROCESS_HUB.with(|x| x.set(true));
}
Some(current_hub)
Some(THREAD_HUB.with(|(hub, is_process_hub)| {
let hub = hub.swap(old_hub);
if was_process_hub {
is_process_hub.set(true);
}
hub
}))
} else {
None
}
Expand All @@ -67,7 +59,7 @@ impl SwitchGuard {

impl Drop for SwitchGuard {
fn drop(&mut self) {
let _ = self.switch_internal();
let _ = self.swap();
}
}

Expand Down Expand Up @@ -154,17 +146,13 @@ impl Hub {
where
F: FnOnce(&Arc<Hub>) -> R,
{
if USE_PROCESS_HUB.with(Cell::get) {
f(&PROCESS_HUB.0)
} else {
// note on safety: this is safe because even though we change the Arc
// by temporary binding we guarantee that the original Arc stays alive.
// For more information see: run
THREAD_HUB.with(|stack| unsafe {
let ptr = stack.get();
f(&*ptr)
})
}
THREAD_HUB.with(|(hub, is_process_hub)| {
if is_process_hub.get() {
f(&PROCESS_HUB.0)
} else {
f(&hub.load())
}
})
}

/// Binds a hub to the current thread for the duration of the call.
Expand Down

0 comments on commit a931084

Please sign in to comment.