mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-29 20:18:13 +08:00
Make the arena unwind safe and the slot locks poison tolerant
This commit is contained in:
@@ -22,6 +22,9 @@ struct DropEntry {
|
|||||||
unsafe impl Sync for Arena {}
|
unsafe impl Sync for Arena {}
|
||||||
unsafe impl Send for Arena {}
|
unsafe impl Send for Arena {}
|
||||||
|
|
||||||
|
impl std::panic::UnwindSafe for Arena {}
|
||||||
|
impl std::panic::RefUnwindSafe for Arena {}
|
||||||
|
|
||||||
impl Arena {
|
impl Arena {
|
||||||
pub fn new(capacity: usize) -> Self {
|
pub fn new(capacity: usize) -> Self {
|
||||||
let buf = (0..capacity).map(|_| UnsafeCell::new(MaybeUninit::uninit())).collect();
|
let buf = (0..capacity).map(|_| UnsafeCell::new(MaybeUninit::uninit())).collect();
|
||||||
@@ -211,6 +214,33 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn panics_leave_the_arena_coherent() {
|
||||||
|
fn assert_ref_unwind_safe<T: std::panic::RefUnwindSafe>() {}
|
||||||
|
assert_ref_unwind_safe::<Arena>();
|
||||||
|
|
||||||
|
static DROPS: AtomicU32 = AtomicU32::new(0);
|
||||||
|
struct Probe(#[allow(dead_code)] String);
|
||||||
|
impl Drop for Probe {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
DROPS.fetch_add(1, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut arena = Arena::new(1024);
|
||||||
|
let cell = ArenaCell::new();
|
||||||
|
let result = std::panic::catch_unwind(|| {
|
||||||
|
let (_, weak) = arena.alloc(Probe("pre-panic".into())).unwrap();
|
||||||
|
cell.store(weak);
|
||||||
|
panic!("mid-eval");
|
||||||
|
});
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert!(cell.load(&arena).is_some(), "the generation is still live after the caught panic");
|
||||||
|
arena.reset();
|
||||||
|
assert_eq!(DROPS.load(Ordering::Relaxed), 1, "reset reclaims pre-panic allocations");
|
||||||
|
assert!(cell.load(&arena).is_none(), "the bump kills stale handles");
|
||||||
|
assert!(arena.alloc(0u32).is_some(), "the arena stays usable");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drop_glue_runs_on_reset() {
|
fn drop_glue_runs_on_reset() {
|
||||||
static DROPS: AtomicU32 = AtomicU32::new(0);
|
static DROPS: AtomicU32 = AtomicU32::new(0);
|
||||||
|
|||||||
@@ -316,7 +316,7 @@ pub(crate) fn generate_gnode_code(crate_ident: &CrateIdent, parsed: &ParsedNodeF
|
|||||||
let slot_check = quote! {
|
let slot_check = quote! {
|
||||||
let __key = #core_types::wire::cache_key(__input);
|
let __key = #core_types::wire::cache_key(__input);
|
||||||
{
|
{
|
||||||
let __entries = self.slot.lock().unwrap();
|
let __entries = self.slot.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||||
if let Some(__state) = __entries.get(&__key) {
|
if let Some(__state) = __entries.get(&__key) {
|
||||||
return match __state {
|
return match __state {
|
||||||
Some(value) => __cell.merge(value.clone()),
|
Some(value) => __cell.merge(value.clone()),
|
||||||
@@ -347,13 +347,13 @@ pub(crate) fn generate_gnode_code(crate_ident: &CrateIdent, parsed: &ParsedNodeF
|
|||||||
let completion = future_completion(&parsed.output_type);
|
let completion = future_completion(&parsed.output_type);
|
||||||
quote! {
|
quote! {
|
||||||
#slot_check
|
#slot_check
|
||||||
self.slot.lock().unwrap().insert(__key, None);
|
self.slot.lock().unwrap_or_else(std::sync::PoisonError::into_inner).insert(__key, None);
|
||||||
let __slot = std::sync::Arc::clone(&self.slot);
|
let __slot = std::sync::Arc::clone(&self.slot);
|
||||||
#(#snapshot_binding)*
|
#(#snapshot_binding)*
|
||||||
let __future = self::#fn_name(#(#future_args),*);
|
let __future = self::#fn_name(#(#future_args),*);
|
||||||
_runtime.0.spawn(_source, Box::pin(async move {
|
_runtime.0.spawn(_source, Box::pin(async move {
|
||||||
let __value = #completion;
|
let __value = #completion;
|
||||||
__slot.lock().unwrap().insert(__key, Some(__value));
|
__slot.lock().unwrap_or_else(std::sync::PoisonError::into_inner).insert(__key, Some(__value));
|
||||||
}));
|
}));
|
||||||
#inflight
|
#inflight
|
||||||
}
|
}
|
||||||
@@ -384,11 +384,11 @@ pub(crate) fn generate_gnode_code(crate_ident: &CrateIdent, parsed: &ParsedNodeF
|
|||||||
#slot_check
|
#slot_check
|
||||||
#placeholder_binding
|
#placeholder_binding
|
||||||
#acquire
|
#acquire
|
||||||
self.slot.lock().unwrap().insert(__key, None);
|
self.slot.lock().unwrap_or_else(std::sync::PoisonError::into_inner).insert(__key, None);
|
||||||
let __slot = std::sync::Arc::clone(&self.slot);
|
let __slot = std::sync::Arc::clone(&self.slot);
|
||||||
_runtime.0.spawn(_source, Box::pin(async move {
|
_runtime.0.spawn(_source, Box::pin(async move {
|
||||||
let __value = #completion;
|
let __value = #completion;
|
||||||
__slot.lock().unwrap().insert(__key, Some(__value));
|
__slot.lock().unwrap_or_else(std::sync::PoisonError::into_inner).insert(__key, Some(__value));
|
||||||
}));
|
}));
|
||||||
#spawn_return
|
#spawn_return
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user