add pthread_atfork interface
authorRich Felker <dalias@aerifal.cx>
Sat, 19 Feb 2011 00:52:42 +0000 (19:52 -0500)
committerRich Felker <dalias@aerifal.cx>
Sat, 19 Feb 2011 00:52:42 +0000 (19:52 -0500)
note that this presently does not handle consistency of the libc's own
global state during forking. as per POSIX 2008, if the parent process
was threaded, the child process may only call async-signal-safe
functions until one of the exec-family functions is called, so the
current behavior is believed to be conformant even if non-ideal. it
may be improved at some later time.

include/pthread.h
src/internal/libc.h
src/process/fork.c
src/thread/pthread_atfork.c [new file with mode: 0644]

index 749a0e8c01f62eb8d8d7a59a290f7d344f9729b8..19199468c9b4dacfdd74d50cd81576840fc1641b 100644 (file)
@@ -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 *);
index e353f36354ad521f38fd6bd62e9703e789cfaca7..ea221b6f9a4deeaba93e0879aeb333298009401f 100644 (file)
@@ -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;
 
 
index 1213f0f509e93d5e2f787862ccc6804ab5ab1f46..0638ed67db74df731bdfab80f4e4d05e12be7981 100644 (file)
@@ -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 (file)
index 0000000..0773dc8
--- /dev/null
@@ -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;
+}