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 *);
volatile int threads_minus_1;
int (*rsyscall)(int, long, long, long, long, long, long);
void (**tsd_keys)(void *);
+ void (*fork_handler)(int);
} libc;
#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;
}
--- /dev/null
+#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;
+}