Skip to content

Commit

Permalink
use a dedicated function for registering atfork
Browse files Browse the repository at this point in the history
  • Loading branch information
nivkner committed Oct 26, 2021
1 parent 4c7334a commit 96c59c6
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 43 deletions.
2 changes: 2 additions & 0 deletions src/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use core::ops::{Deref, DerefMut};

use Dlmalloc;

pub use sys::enable_alloc_after_fork;

/// An instance of a "global allocator" backed by `Dlmalloc`
///
/// This API requires the `global` feature is activated, and this type
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use core::ptr;
use sys::System;

#[cfg(feature = "global")]
pub use self::global::GlobalDlmalloc;
pub use self::global::{enable_alloc_after_fork, GlobalDlmalloc};

mod dlmalloc;
#[cfg(feature = "global")]
Expand Down
55 changes: 34 additions & 21 deletions src/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,34 +75,47 @@ unsafe impl Allocator for System {

#[cfg(feature = "global")]
pub fn acquire_global_lock() {
static mut FORK_PROTECTED: bool = false;
unsafe { assert_eq!(libc::pthread_mutex_lock(&mut LOCK), 0) }
}

unsafe {
assert_eq!(libc::pthread_mutex_lock(&mut LOCK), 0);
if !FORK_PROTECTED {
// ensures that if a process forks,
// it will acquire the lock before any other thread,
// protecting it from deadlock,
// when the child is created with only that thread.
libc::pthread_atfork(
Some(_acquire_global_lock),
Some(_release_global_lock),
Some(_release_global_lock),
);
FORK_PROTECTED = true;
}
}
#[cfg(feature = "global")]
pub fn release_global_lock() {
unsafe { assert_eq!(libc::pthread_mutex_unlock(&mut LOCK), 0) }
}

#[cfg(feature = "global")]
/// allows the allocator to remain unsable in the child process,
/// after a call to `fork(2)`
///
/// #Safety
///
/// if used, this function must be called,
/// before any allocations are made with the global allocator.
pub unsafe fn enable_alloc_after_fork() {
// atfork must only be called once, to avoid a deadlock,
// where the handler attempts to acquire the global lock twice
static mut FORK_PROTECTED: bool = false;

unsafe extern "C" fn _acquire_global_lock() {
assert_eq!(libc::pthread_mutex_lock(&mut LOCK), 0)
acquire_global_lock()
}

unsafe extern "C" fn _release_global_lock() {
release_global_lock()
}
}

#[cfg(feature = "global")]
pub fn release_global_lock() {
unsafe { assert_eq!(libc::pthread_mutex_unlock(&mut LOCK), 0) }
acquire_global_lock();
// if a process forks,
// it will acquire the lock before any other thread,
// protecting it from deadlock,
// due to the child being created with only the calling thread.
if !FORK_PROTECTED {
libc::pthread_atfork(
Some(_acquire_global_lock),
Some(_release_global_lock),
Some(_release_global_lock),
);
FORK_PROTECTED = true;
}
release_global_lock();
}
55 changes: 34 additions & 21 deletions src/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,34 +63,47 @@ unsafe impl Allocator for System {

#[cfg(feature = "global")]
pub fn acquire_global_lock() {
static mut FORK_PROTECTED: bool = false;
unsafe { assert_eq!(libc::pthread_mutex_lock(&mut LOCK), 0) }
}

unsafe {
assert_eq!(libc::pthread_mutex_lock(&mut LOCK), 0);
if !FORK_PROTECTED {
// ensures that if a process forks,
// it will acquire the lock before any other thread,
// protecting it from deadlock,
// when the child is created with only that thread.
libc::pthread_atfork(
Some(_acquire_global_lock),
Some(_release_global_lock),
Some(_release_global_lock),
);
FORK_PROTECTED = true;
}
}
#[cfg(feature = "global")]
pub fn release_global_lock() {
unsafe { assert_eq!(libc::pthread_mutex_unlock(&mut LOCK), 0) }
}

#[cfg(feature = "global")]
/// allows the allocator to remain unsable in the child process,
/// after a call to `fork(2)`
///
/// #Safety
///
/// if used, this function must be called,
/// before any allocations are made with the global allocator.
pub unsafe fn enable_alloc_after_fork() {
// atfork must only be called once, to avoid a deadlock,
// where the handler attempts to acquire the global lock twice
static mut FORK_PROTECTED: bool = false;

unsafe extern "C" fn _acquire_global_lock() {
assert_eq!(libc::pthread_mutex_lock(&mut LOCK), 0)
acquire_global_lock()
}

unsafe extern "C" fn _release_global_lock() {
release_global_lock()
}
}

#[cfg(feature = "global")]
pub fn release_global_lock() {
unsafe { assert_eq!(libc::pthread_mutex_unlock(&mut LOCK), 0) }
acquire_global_lock();
// if a process forks,
// it will acquire the lock before any other thread,
// protecting it from deadlock,
// due to the child being created with only the calling thread.
if !FORK_PROTECTED {
libc::pthread_atfork(
Some(_acquire_global_lock),
Some(_release_global_lock),
Some(_release_global_lock),
);
FORK_PROTECTED = true;
}
release_global_lock();
}
5 changes: 5 additions & 0 deletions src/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,8 @@ pub fn acquire_global_lock() {
pub fn release_global_lock() {
// single threaded, no need!
}

#[cfg(feature = "global")]
pub unsafe fn enable_alloc_after_fork() {
// single threaded, no need!
}

0 comments on commit 96c59c6

Please sign in to comment.