summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2013-09-21 23:35:41 +0200
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2013-09-21 23:35:41 +0200
commit1b99b0ffaf09cd7500c9390704ed56be47882d70 (patch)
treec69f642091ef58854e492f492a521e841eb6b4b3
parentff1ae3d79b2d103f211ad4c600e144ad448a98e6 (diff)
Add pthread_atfork support
* Versions (libc): Add __register_atfork with GLIBC_PRIVATE version. * forward.c: Include <errno.h> (atfork): New structure. (atfork_lock): New mutex. (fork_handlers, fork_last_handler): New variables. (atfork_pthread_prepare, atfork_pthread_parent, atfork_pthread_child): New atfork hooks (__register_atfork): New function. * sysdeps/generic/pt-atfork.c (pthread_atfork): Call __register_atfork.
-rw-r--r--Versions1
-rw-r--r--forward.c105
-rw-r--r--sysdeps/generic/pt-atfork.c2
3 files changed, 107 insertions, 1 deletions
diff --git a/Versions b/Versions
index 3d151cf..41bff96 100644
--- a/Versions
+++ b/Versions
@@ -18,6 +18,7 @@ libc {
__pthread_get_cleanup_stack;
GLIBC_PRIVATE {
__libc_pthread_init;
+ __register_atfork;
}
}
diff --git a/forward.c b/forward.c
index c07d7c0..9e940fb 100644
--- a/forward.c
+++ b/forward.c
@@ -17,6 +17,7 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+#include <errno.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <shlib-compat.h>
@@ -125,3 +126,107 @@ FORWARD (pthread_setcanceltype, (int type, int *oldtype), (type, oldtype), 0)
struct __pthread_cancelation_handler *dummy_list;
FORWARD2 (__pthread_get_cleanup_stack, struct __pthread_cancelation_handler **, (void), (), return &dummy_list);
+
+
+/* Fork interaction */
+
+struct atfork {
+ void (*prepare) (void);
+ void (*parent) (void);
+ void (*child) (void);
+ struct atfork *prev;
+ struct atfork *next;
+};
+
+/* TODO: better locking */
+static struct mutex atfork_lock;
+static struct atfork *fork_handlers, *fork_last_handler;
+
+static void
+atfork_pthread_prepare (void)
+{
+ struct atfork *handlers, *last_handler;
+
+ __mutex_lock (&atfork_lock);
+ handlers = fork_handlers;
+ last_handler = fork_last_handler;
+ __mutex_unlock (&atfork_lock);
+
+ if (!last_handler)
+ return;
+
+ while(1)
+ {
+ if (last_handler->prepare != NULL)
+ last_handler->prepare ();
+ if (last_handler == handlers)
+ break;
+ last_handler = last_handler->prev;
+ }
+}
+text_set_element (_hurd_atfork_prepare_hook, atfork_pthread_prepare);
+
+static void
+atfork_pthread_parent (void)
+{
+ struct atfork *handlers;
+
+ __mutex_lock (&atfork_lock);
+ handlers = fork_handlers;
+ __mutex_unlock (&atfork_lock);
+
+ while (handlers)
+ {
+ if (handlers->parent != NULL)
+ handlers->parent ();
+ handlers = handlers->next;
+ }
+}
+text_set_element (_hurd_atfork_parent_hook, atfork_pthread_parent);
+
+static void
+atfork_pthread_child (void)
+{
+ struct atfork *handlers;
+
+ __mutex_lock (&atfork_lock);
+ handlers = fork_handlers;
+ __mutex_unlock (&atfork_lock);
+
+ while (handlers)
+ {
+ if (handlers->child != NULL)
+ handlers->child ();
+ handlers = handlers->next;
+ }
+}
+text_set_element (_hurd_atfork_child_hook, atfork_pthread_child);
+
+int
+__register_atfork (
+ void (*prepare) (void),
+ void (*parent) (void),
+ void (*child) (void))
+{
+ struct atfork *new = malloc (sizeof (*new));
+ if (!new)
+ return errno;
+
+ new->prepare = prepare;
+ new->parent = parent;
+ new->child = child;
+ new->prev = NULL;
+
+ __mutex_lock (&atfork_lock);
+ new->next = fork_handlers;
+ if (fork_handlers)
+ fork_handlers->prev = new;
+ fork_handlers = new;
+ if (!fork_last_handler)
+ fork_last_handler = new;
+ __mutex_unlock (&atfork_lock);
+
+ return 0;
+}
+
+/* TODO: unregister_atfork, and define UNREGISTER_ATFORK, for module unload support */
diff --git a/sysdeps/generic/pt-atfork.c b/sysdeps/generic/pt-atfork.c
index 32e1e78..ce72e10 100644
--- a/sysdeps/generic/pt-atfork.c
+++ b/sysdeps/generic/pt-atfork.c
@@ -25,5 +25,5 @@ pthread_atfork (void (*prepare) (void),
void (*parent) (void),
void (*child) (void))
{
- return ENOSYS;
+ return __register_atfork (prepare, parent, child);
}