diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2013-09-21 23:35:41 +0200 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2013-09-21 23:35:41 +0200 |
commit | 1b99b0ffaf09cd7500c9390704ed56be47882d70 (patch) | |
tree | c69f642091ef58854e492f492a521e841eb6b4b3 | |
parent | ff1ae3d79b2d103f211ad4c600e144ad448a98e6 (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-- | Versions | 1 | ||||
-rw-r--r-- | forward.c | 105 | ||||
-rw-r--r-- | sysdeps/generic/pt-atfork.c | 2 |
3 files changed, 107 insertions, 1 deletions
@@ -18,6 +18,7 @@ libc { __pthread_get_cleanup_stack; GLIBC_PRIVATE { __libc_pthread_init; + __register_atfork; } } @@ -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); } |