Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace `static mut` with `const`, `static`+`AtomicPtr`, or `static`+`UnsafeCell` #26792

Merged
merged 4 commits into from Jun 5, 2020
@@ -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<T>(std::cell::UnsafeCell<T>);

/// Safety: dereferencing the pointer from `UnsafeCell::get` must involve external synchronization
unsafe impl<T> Sync for UncheckedSyncUnsafeCell<T> {}

static SHARED_STATE: UncheckedSyncUnsafeCell<SharedState> =
UncheckedSyncUnsafeCell(std::cell::UnsafeCell::new(SharedState {
msg2: None,
msg3: None,
msg4: None,
}));

static CONTEXT: AtomicPtr<libc::ucontext_t> = AtomicPtr::new(ptr::null_mut());

type MonitoredThreadId = libc::pid_t;

@@ -37,25 +44,30 @@ struct SharedState {
msg2: Option<PosixSemaphore>,
msg3: Option<PosixSemaphore>,
msg4: Option<PosixSemaphore>,
context: AtomicPtr<libc::ucontext_t>,
}

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");

// 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.
}
// copy the context.
CONTEXT.store(ctx as *mut libc::ucontext_t, Ordering::SeqCst);

// Safety: non-exclusive reference only
// since the sampling thread is accessing this concurrently
let shared_state = unsafe { &*SHARED_STATE.0.get() };

// 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) {
@@ -2750,7 +2750,9 @@ def definition_body(self):
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 @@ def __init__(self, descriptors):

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 @@ def definition_body(self):
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<libc::c_void> =\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 @@ def PrototypeList(config):
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 @@ def PrototypeList(config):
" 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 @@ def RegisterBindings(config):

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
@@ -515,22 +515,16 @@ impl EventTarget {
let name = CString::new(&**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,
b"colno\0" as *const u8 as *const c_char,
b"error\0" as *const u8 as *const c_char,
];
let is_error = ty == &atom!("error") && self.is::<Window>();
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 {
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.