WIP: pthread_atfork
WIP mainly because we *should* use thread locals, but #[thread_local] causes segfaults.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
use core::{mem, ptr, slice};
|
||||
|
||||
use alloc::collections::LinkedList;
|
||||
use c_str::CStr;
|
||||
use header::errno;
|
||||
use header::limits;
|
||||
@@ -10,9 +11,9 @@ use header::sys_ioctl;
|
||||
use header::sys_time;
|
||||
use header::termios;
|
||||
use header::time::timespec;
|
||||
use platform;
|
||||
use platform::types::*;
|
||||
use platform::{Pal, Sys};
|
||||
use platform;
|
||||
|
||||
pub use self::brk::*;
|
||||
pub use self::getopt::*;
|
||||
@@ -42,6 +43,17 @@ pub const STDIN_FILENO: c_int = 0;
|
||||
pub const STDOUT_FILENO: c_int = 1;
|
||||
pub const STDERR_FILENO: c_int = 2;
|
||||
|
||||
#[thread_local]
|
||||
pub static mut fork_hooks_static: Option<[LinkedList<extern "C" fn()>; 3]> = None;
|
||||
|
||||
unsafe fn init_fork_hooks<'a>() -> &'a mut [LinkedList<extern "C" fn()>; 3] {
|
||||
// Transmute the lifetime so we can return here. Should be safe as
|
||||
// long as one does not access the original fork_hooks.
|
||||
mem::transmute(fork_hooks_static.get_or_insert_with(|| {
|
||||
[LinkedList::new(), LinkedList::new(), LinkedList::new()]
|
||||
}))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn _exit(status: c_int) {
|
||||
Sys::exit(status)
|
||||
@@ -214,7 +226,21 @@ pub extern "C" fn fdatasync(fildes: c_int) -> c_int {
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn fork() -> pid_t {
|
||||
Sys::fork()
|
||||
let fork_hooks = unsafe { init_fork_hooks() };
|
||||
for prepare in &fork_hooks[0] {
|
||||
prepare();
|
||||
}
|
||||
let pid = Sys::fork();
|
||||
if pid == 0 {
|
||||
for child in &fork_hooks[2] {
|
||||
child();
|
||||
}
|
||||
} else if pid != -1 {
|
||||
for parent in &fork_hooks[1] {
|
||||
parent();
|
||||
}
|
||||
}
|
||||
pid
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -456,9 +482,16 @@ pub extern "C" fn pthread_atfork(
|
||||
parent: Option<extern "C" fn()>,
|
||||
child: Option<extern "C" fn()>,
|
||||
) -> c_int {
|
||||
// TODO: WIP implementation available in "atfork" branch. It's
|
||||
// segfaulting at the thread-local stuff, both in Unix and Redox.
|
||||
// unimplemented!();
|
||||
let fork_hooks = unsafe { init_fork_hooks() };
|
||||
if let Some(prepare) = prepare {
|
||||
fork_hooks[0].push_back(prepare);
|
||||
}
|
||||
if let Some(parent) = parent {
|
||||
fork_hooks[1].push_back(parent);
|
||||
}
|
||||
if let Some(child) = child {
|
||||
fork_hooks[2].push_back(child);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ EXPECT_NAMES=\
|
||||
unistd/dup \
|
||||
unistd/exec \
|
||||
unistd/fchdir \
|
||||
unistd/fork \
|
||||
unistd/fsync \
|
||||
unistd/ftruncate \
|
||||
unistd/getopt \
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
Hello from prepare
|
||||
Hello from child
|
||||
Hello from parent
|
||||
@@ -0,0 +1,29 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "test_helpers.h"
|
||||
|
||||
void prepare() {
|
||||
puts("Hello from prepare");
|
||||
}
|
||||
void parent() {
|
||||
// Make sure we print in the right order and also don't exit
|
||||
// before the fork does.
|
||||
int us_status = usleep(1000);
|
||||
ERROR_IF(usleep, us_status, == -1);
|
||||
UNEXP_IF(usleep, us_status, != 0);
|
||||
|
||||
puts("Hello from parent");
|
||||
}
|
||||
void child() {
|
||||
puts("Hello from child");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int status = pthread_atfork(prepare, parent, child);
|
||||
ERROR_IF(pthread_atfork, status, == -1);
|
||||
|
||||
int pid = fork();
|
||||
ERROR_IF(fork, pid, == -1);
|
||||
}
|
||||
Reference in New Issue
Block a user