diff --git a/components/background_hang_monitor/sampler_linux.rs b/components/background_hang_monitor/sampler_linux.rs index 3b60203d208..b0561c743d6 100644 --- a/components/background_hang_monitor/sampler_linux.rs +++ b/components/background_hang_monitor/sampler_linux.rs @@ -23,12 +23,19 @@ use unwind_sys::{ #[link(name = "lzma")] extern "C" {} -static mut SHARED_STATE: SharedState = SharedState { - msg2: None, - msg3: None, - msg4: None, - context: AtomicPtr::new(ptr::null_mut()), -}; +struct UncheckedSyncUnsafeCell(std::cell::UnsafeCell); + +/// Safety: dereferencing the pointer from `UnsafeCell::get` must involve external synchronization +unsafe impl Sync for UncheckedSyncUnsafeCell {} + +static SHARED_STATE: UncheckedSyncUnsafeCell = + UncheckedSyncUnsafeCell(std::cell::UnsafeCell::new(SharedState { + msg2: None, + msg3: None, + msg4: None, + })); + +static CONTEXT: AtomicPtr = AtomicPtr::new(ptr::null_mut()); type MonitoredThreadId = libc::pid_t; @@ -37,25 +44,30 @@ struct SharedState { msg2: Option, msg3: Option, msg4: Option, - context: AtomicPtr, } fn clear_shared_state() { + // Safety: this is only called from the sampling thread (there’s only one) + // Sampled threads only access SHARED_STATE in their signal handler. + // This signal and the semaphores in SHARED_STATE provide the necessary synchronization. unsafe { - SHARED_STATE.msg2 = None; - SHARED_STATE.msg3 = None; - SHARED_STATE.msg4 = None; - SHARED_STATE.context = AtomicPtr::new(ptr::null_mut()); + let shared_state = &mut *SHARED_STATE.0.get(); + shared_state.msg2 = None; + shared_state.msg3 = None; + shared_state.msg4 = None; } + CONTEXT.store(ptr::null_mut(), Ordering::SeqCst); } fn reset_shared_state() { + // Safety: same as clear_shared_state unsafe { - SHARED_STATE.msg2 = Some(PosixSemaphore::new(0).expect("valid semaphore")); - SHARED_STATE.msg3 = Some(PosixSemaphore::new(0).expect("valid semaphore")); - SHARED_STATE.msg4 = Some(PosixSemaphore::new(0).expect("valid semaphore")); - SHARED_STATE.context = AtomicPtr::new(ptr::null_mut()); + let shared_state = &mut *SHARED_STATE.0.get(); + shared_state.msg2 = Some(PosixSemaphore::new(0).expect("valid semaphore")); + shared_state.msg3 = Some(PosixSemaphore::new(0).expect("valid semaphore")); + shared_state.msg4 = Some(PosixSemaphore::new(0).expect("valid semaphore")); } + CONTEXT.store(ptr::null_mut(), Ordering::SeqCst); } struct PosixSemaphore { @@ -194,16 +206,18 @@ impl Sampler for LinuxSampler { // signal the thread, wait for it to tell us state was copied. send_sigprof(self.thread_id); - unsafe { - SHARED_STATE - .msg2 - .as_ref() - .unwrap() - .wait_through_intr() - .expect("msg2 failed"); - } - let context = unsafe { SHARED_STATE.context.load(Ordering::SeqCst) }; + // Safety: non-exclusive reference only + // since sampled threads are accessing this concurrently + let shared_state = unsafe { &*SHARED_STATE.0.get() }; + shared_state + .msg2 + .as_ref() + .unwrap() + .wait_through_intr() + .expect("msg2 failed"); + + let context = CONTEXT.load(Ordering::SeqCst); let mut cursor = mem::MaybeUninit::uninit(); let ret = unsafe { unw_init_local(cursor.as_mut_ptr(), context) }; let result = if ret == UNW_ESUCCESS { @@ -231,24 +245,23 @@ impl Sampler for LinuxSampler { }; // signal the thread to continue. - unsafe { - SHARED_STATE - .msg3 - .as_ref() - .unwrap() - .post() - .expect("msg3 failed"); - } + shared_state + .msg3 + .as_ref() + .unwrap() + .post() + .expect("msg3 failed"); // wait for thread to continue. - unsafe { - SHARED_STATE - .msg4 - .as_ref() - .unwrap() - .wait_through_intr() - .expect("msg4 failed"); - } + shared_state + .msg4 + .as_ref() + .unwrap() + .wait_through_intr() + .expect("msg4 failed"); + + // No-op, but marks the end of the shared borrow + drop(shared_state); clear_shared_state(); @@ -271,26 +284,27 @@ extern "C" fn sigprof_handler( ctx: *mut libc::c_void, ) { assert_eq!(sig, libc::SIGPROF); - unsafe { - // copy the context. - SHARED_STATE - .context - .store(ctx as *mut libc::ucontext_t, Ordering::SeqCst); - // Tell the sampler we copied the context. - SHARED_STATE.msg2.as_ref().unwrap().post().expect("posted"); + // copy the context. + CONTEXT.store(ctx as *mut libc::ucontext_t, Ordering::SeqCst); - // Wait for sampling to finish. - SHARED_STATE - .msg3 - .as_ref() - .unwrap() - .wait_through_intr() - .expect("msg3 wait succeeded"); + // Safety: non-exclusive reference only + // since the sampling thread is accessing this concurrently + let shared_state = unsafe { &*SHARED_STATE.0.get() }; - // OK we are done! - SHARED_STATE.msg4.as_ref().unwrap().post().expect("posted"); - // DO NOT TOUCH shared state here onwards. - } + // Tell the sampler we copied the context. + shared_state.msg2.as_ref().unwrap().post().expect("posted"); + + // Wait for sampling to finish. + shared_state + .msg3 + .as_ref() + .unwrap() + .wait_through_intr() + .expect("msg3 wait succeeded"); + + // OK we are done! + shared_state.msg4.as_ref().unwrap().post().expect("posted"); + // DO NOT TOUCH shared state here onwards. } fn send_sigprof(to: libc::pid_t) { diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 0b1187a07fb..b0361d6ca47 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2750,7 +2750,9 @@ class CGWrapMethod(CGAbstractMethod): unforgeable = CopyUnforgeablePropertiesToInstance(self.descriptor) if self.descriptor.proxy: create = """ -let handler = RegisterBindings::PROXY_HANDLERS[PrototypeList::Proxies::%(concreteType)s as usize]; +let handler: *const libc::c_void = + RegisterBindings::proxy_handlers::%(concreteType)s + .load(std::sync::atomic::Ordering::Acquire); rooted!(in(*cx) let obj = NewProxyObject( *cx, handler, @@ -6744,7 +6746,10 @@ class CGRegisterProxyHandlersMethod(CGAbstractMethod): def definition_body(self): return CGList([ - CGGeneric("PROXY_HANDLERS[Proxies::%s as usize] = Bindings::%s::DefineProxyHandler();" + CGGeneric("proxy_handlers::%s.store(\n" + " Bindings::%s::DefineProxyHandler() as *mut _,\n" + " std::sync::atomic::Ordering::Release,\n" + ");" % (desc.name, '::'.join([desc.name + 'Binding'] * 2))) for desc in self.descriptors ], "\n") @@ -6753,10 +6758,18 @@ class CGRegisterProxyHandlersMethod(CGAbstractMethod): class CGRegisterProxyHandlers(CGThing): def __init__(self, config): descriptors = config.getDescriptors(proxy=True) - length = len(descriptors) self.root = CGList([ - CGGeneric("pub static mut PROXY_HANDLERS: [*const libc::c_void; %d] = [0 as *const libc::c_void; %d];" - % (length, length)), + CGGeneric( + "#[allow(non_upper_case_globals)]\n" + + "pub mod proxy_handlers {\n" + + "".join( + " pub static %s: std::sync::atomic::AtomicPtr =\n" + " std::sync::atomic::AtomicPtr::new(std::ptr::null_mut());\n" + % desc.name + for desc in descriptors + ) + + "}\n" + ), CGRegisterProxyHandlersMethod(descriptors), ], "\n") @@ -7606,8 +7619,6 @@ class GlobalGenRoots(): for d in config.getDescriptors(hasInterfaceObject=True) if d.shouldHaveGetConstructorObjectMethod()]) - proxies = [d.name for d in config.getDescriptors(proxy=True)] - return CGList([ CGGeneric(AUTOGENERATED_WARNING_COMMENT), CGGeneric("pub const PROTO_OR_IFACE_LENGTH: usize = %d;\n" % (len(protos) + len(constructors))), @@ -7624,7 +7635,6 @@ class GlobalGenRoots(): " debug_assert!(proto_id < ID::Last as u16);\n" " INTERFACES[proto_id as usize]\n" "}\n\n"), - CGNonNamespacedEnum('Proxies', proxies, 0, deriving="PartialEq, Copy, Clone"), ]) @staticmethod @@ -7636,8 +7646,6 @@ class GlobalGenRoots(): return CGImports(code, descriptors=[], callbacks=[], dictionaries=[], enums=[], typedefs=[], imports=[ 'crate::dom::bindings::codegen::Bindings', - 'crate::dom::bindings::codegen::PrototypeList::Proxies', - 'libc', ], config=config, ignored_warnings=[]) @staticmethod diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs index b39bf977c5b..7018300b107 100644 --- a/components/script/dom/eventtarget.rs +++ b/components/script/dom/eventtarget.rs @@ -515,8 +515,8 @@ impl EventTarget { let name = CString::new(format!("on{}", &**ty)).unwrap(); // Step 3.9, subsection ParameterList - static mut ARG_NAMES: [*const c_char; 1] = [b"event\0" as *const u8 as *const c_char]; - static mut ERROR_ARG_NAMES: [*const c_char; 5] = [ + const ARG_NAMES: &[*const c_char] = &[b"event\0" as *const u8 as *const c_char]; + const ERROR_ARG_NAMES: &[*const c_char] = &[ b"event\0" as *const u8 as *const c_char, b"source\0" as *const u8 as *const c_char, b"lineno\0" as *const u8 as *const c_char, @@ -524,13 +524,7 @@ impl EventTarget { b"error\0" as *const u8 as *const c_char, ]; let is_error = ty == &atom!("error") && self.is::(); - let args = unsafe { - if is_error { - &ERROR_ARG_NAMES[..] - } else { - &ARG_NAMES[..] - } - }; + let args = if is_error { ERROR_ARG_NAMES } else { ARG_NAMES }; let cx = window.get_cx(); let options = unsafe {