diff options
-rw-r--r-- | ChangeLog | 17 | ||||
-rw-r--r-- | cleanup.c | 5 | ||||
-rw-r--r-- | fork.c | 84 | ||||
-rw-r--r-- | implement.h | 12 | ||||
-rw-r--r-- | pthread.h | 4 |
5 files changed, 102 insertions, 20 deletions
@@ -1,5 +1,22 @@ Fri Jul 24 16:33:17 1998 Ross Johnson <rpj@swan.canberra.edu.au> + * fork.c (pthread_atfork): Add all the necessary push calls. + Local implementation semantics: + If we get an ENOMEM at any time then ALL handlers + (including those from previous pthread_atfork() calls) will be + popped off each of the three atfork stacks before we return. + (fork): Add all the necessary pop calls. Add the thread cancellation + and join calls to the child fork. + Add #includes. + + * implement.h: (_pthread_handler_push): Fix return type and stack arg + type in prototype. + (_pthread_handler_pop): Fix stack arg type in prototype. + (_pthread_handler_pop_all): Fix stack arg type in prototype. + + * cleanup.c (_pthread_handler_push): Change return type to int and + return ENOMEM if malloc() fails. + * sync.c (pthread_detach): Use equality test, not assignment. * create.c (_pthread_start_call): Add call to Win32 CloseHandle() @@ -9,7 +9,7 @@ #include "pthread.h" #include "implement.h" -void +int _pthread_handler_push(int stack, int poporder, void (*routine)(void *), @@ -27,7 +27,7 @@ _pthread_handler_push(int stack, if (new == NULL) { - /* FIXME: INTERNAL ERROR */ + return ENOMEM; } new->routine = routine; @@ -60,6 +60,7 @@ _pthread_handler_push(int stack, next = new; } } + return 0; } void @@ -5,33 +5,73 @@ * Implementation of fork() for POSIX threads. */ +#include "pthread.h" +#include "implement.h" + int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) { - /* Push handlers (unless NULL) onto their respective stacks. */ + /* Push handlers (unless NULL) onto their respective stacks. + + Local implementation semantics: + If we get an ENOMEM at any time in here then ALL handlers + (including those from previous pthread_atfork() calls) will be + popped off each of the three atfork stacks before we return. */ + + int ret = 0; if (prepare != NULL) { /* Push prepare. */ - /* If push fails, return ENOMEM. */ + if (_pthread_handler_push(_PTHREAD_FORKPREPARE_STACK, + _PTHREAD_HANDLER_POP_FIFO, + (void (*prepare)(void *)), NULL) == ENOMEM) + { + ret = ENOMEM; + } } - if (parent != NULL) + if (parent != NULL && + ret != ENOMEM) { /* Push parent. */ - /* If push fails, return ENOMEM. */ + if (_pthread_handler_push(_PTHREAD_FORKPARENT_STACK, + _PTHREAD_HANDLER_POP_LIFO, + (void (*parent)(void *)), NULL) == ENOMEM) + { + ret = ENOMEM; + } } - if (child != NULL) + if (child != NULL && + ret != ENOMEM) { /* Push child. */ - /* If push fails, return ENOMEM. */ + if (_pthread_handler_push(_PTHREAD_FORKCHILD_STACK, + _PTHREAD_HANDLER_POP_LIFO, + (void (*child)(void *)), arg) == ENOMEM) + { + ret = ENOMEM; + } + } + + if (ret == ENOMEM) + { + /* Pop all handlers without executing them before we return + the error. */ + _pthread_handler_pop_all(_PTHREAD_FORKPREPARE_STACK, + _PTHREAD_HANDLER_NOEXECUTE); + + _pthread_handler_pop_all(_PTHREAD_FORKPARENT_STACK, + _PTHREAD_HANDLER_NOEXECUTE); + + _pthread_handler_pop_all(_PTHREAD_FORKCHILD_STACK, + _PTHREAD_HANDLER_NOEXECUTE); } - /* Everything is okay. */ - return 0; + return ret; } /* It looks like the GNU linker is capable of selecting this version of @@ -44,19 +84,43 @@ fork() pid_t pid; /* Pop prepare handlers here. */ + _pthread_handler_pop_all(_PTHREAD_FORKPREPARE_STACK, + _PTHREAD_HANDLER_EXECUTE); /* Now call Cygwin32's fork(). */ if ((pid = _fork()) > 0) { - /* Pop parent handlers. */ + /* PARENT */ + /* Clear the child handler stack. */ + _pthread_handler_pop_all(_PTHREAD_FORKCHILD_STACK, + _PTHREAD_HANDLER_NOEXECUTE); + + /* Pop parent handlers and execute them. */ + _pthread_handler_pop_all(_PTHREAD_FORKPARENT_STACK, + _PTHREAD_HANDLER_EXECUTE); + + /* At this point all three atfork stacks are empty. */ return pid; } else { - /* Pop child handlers. */ + /* CHILD */ + /* Clear the parent handler stack. */ + _pthread_handler_pop_all(_PTHREAD_FORKPARENT_STACK, + _PTHREAD_HANDLER_NOEXECUTE); + + /* Pop child handlers and execute them. */ + _pthread_handler_pop_all(_PTHREAD_FORKCHILD_STACK, + _PTHREAD_HANDLER_EXECUTE); + + /* At this point all three atfork stacks are empty. */ + /* Terminate all threads except pthread_self() using pthread_cancel(). */ + _pthread_cancel_all_not_self(); + _pthread_join_all_not_self(); + return 0; } diff --git a/implement.h b/implement.h index b72e273..4a9a5ad 100644 --- a/implement.h +++ b/implement.h @@ -66,15 +66,15 @@ extern "C" { /* Generic handler push and pop routines. */ -void _pthread_handler_push(_pthread_handler_node_t ** stacktop, - int poporder, - void (*routine)(void *), - void *arg); +int _pthread_handler_push(int stack, + int poporder, + void (*routine)(void *), + void *arg); -void _pthread_handler_pop(_pthread_handler_node_t ** stacktop, +void _pthread_handler_pop(int stack, int execute); -void _pthread_handler_pop_all(_pthread_handler_node_t ** stacktop, +void _pthread_handler_pop_all(int stack, int execute); /* Primitives to manage threads table entries. */ @@ -276,8 +276,8 @@ enum { #define pthread_cleanup_push(routine, arg) \ { \ - _pthread_handler_push(_PTHREAD_CLEANUP_STACK, \ - _PTHREAD_HANDLER_POP_LIFO, routine, arg); + (void ) _pthread_handler_push(_PTHREAD_CLEANUP_STACK, \ + _PTHREAD_HANDLER_POP_LIFO, routine, arg); #ifdef pthread_cleanup_pop #undef pthread_cleanup_pop |