diff options
| -rw-r--r-- | include/pthread.h | 2 | ||||
| -rw-r--r-- | src/internal/libc.h | 1 | ||||
| -rw-r--r-- | src/process/fork.c | 9 | ||||
| -rw-r--r-- | src/thread/pthread_atfork.c | 48 | 
4 files changed, 57 insertions, 3 deletions
| diff --git a/include/pthread.h b/include/pthread.h index 749a0e8c..19199468 100644 --- a/include/pthread.h +++ b/include/pthread.h @@ -162,6 +162,8 @@ int pthread_barrierattr_getpshared(const pthread_barrierattr_t *, int *);  int pthread_barrierattr_init(pthread_barrierattr_t *);  int pthread_barrierattr_setpshared(pthread_barrierattr_t *, int); +int pthread_atfork(void (*)(void), void (*)(void), void (*)(void)); +  #include <bits/pthread.h>  int __setjmp(void *); diff --git a/src/internal/libc.h b/src/internal/libc.h index e353f363..ea221b6f 100644 --- a/src/internal/libc.h +++ b/src/internal/libc.h @@ -15,6 +15,7 @@ extern struct libc {  	volatile int threads_minus_1;  	int (*rsyscall)(int, long, long, long, long, long, long);  	void (**tsd_keys)(void *); +	void (*fork_handler)(int);  } libc; diff --git a/src/process/fork.c b/src/process/fork.c index 1213f0f5..0638ed67 100644 --- a/src/process/fork.c +++ b/src/process/fork.c @@ -1,9 +1,12 @@  #include <unistd.h>  #include "syscall.h" - -/* FIXME: add support for atfork stupidity */ +#include "libc.h"  pid_t fork(void)  { -	return syscall0(__NR_fork); +	pid_t ret; +	if (libc.fork_handler) libc.fork_handler(-1); +	ret = syscall0(__NR_fork); +	if (libc.fork_handler) libc.fork_handler(!ret); +	return ret;  } diff --git a/src/thread/pthread_atfork.c b/src/thread/pthread_atfork.c new file mode 100644 index 00000000..0773dc8f --- /dev/null +++ b/src/thread/pthread_atfork.c @@ -0,0 +1,48 @@ +#include <pthread.h> +#include "libc.h" + +static struct atfork_funcs { +	void (*prepare)(void); +	void (*parent)(void); +	void (*child)(void); +	struct atfork_funcs *prev, *next; +} *funcs; + +static int lock; + +static void fork_handler(int who) +{ +	struct atfork_funcs *p; +	if (who < 0) { +		LOCK(&lock); +		for (p=funcs; p; p = p->next) { +			if (p->prepare) p->prepare(); +			funcs = p; +		} +	} else { +		for (p=funcs; p; p = p->prev) { +			if (!who && p->parent) p->parent(); +			else if (who && p->child) p->child(); +			funcs = p; +		} +		UNLOCK(&lock); +	} +} + +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) +{ +	struct atfork_funcs *new = malloc(sizeof *new); +	if (!new) return -1; + +	LOCK(&lock); +	libc.fork_handler = fork_handler; +	new->next = funcs; +	new->prev = 0; +	new->prepare = prepare; +	new->parent = parent; +	new->child = child; +	if (funcs) funcs->prev = new; +	funcs = new; +	UNLOCK(&lock); +	return 0; +} | 
