WIP: pthread_atfork

WIP mainly because we *should* use thread locals, but #[thread_local]
causes segfaults.
This commit is contained in:
jD91mZM2
2019-04-28 17:14:45 +02:00
parent f9dca89c1f
commit e35f22b3df
5 changed files with 71 additions and 5 deletions
+38 -5
View File
@@ -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
}
+1
View File
@@ -77,6 +77,7 @@ EXPECT_NAMES=\
unistd/dup \
unistd/exec \
unistd/fchdir \
unistd/fork \
unistd/fsync \
unistd/ftruncate \
unistd/getopt \
View File
+3
View File
@@ -0,0 +1,3 @@
Hello from prepare
Hello from child
Hello from parent
+29
View File
@@ -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);
}