summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog17
-rw-r--r--cleanup.c5
-rw-r--r--fork.c84
-rw-r--r--implement.h12
-rw-r--r--pthread.h4
5 files changed, 102 insertions, 20 deletions
diff --git a/ChangeLog b/ChangeLog
index eb072c6..bd2acf9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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()
diff --git a/cleanup.c b/cleanup.c
index 168b75f..9bf4a68 100644
--- a/cleanup.c
+++ b/cleanup.c
@@ -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
diff --git a/fork.c b/fork.c
index 0b27558..534effc 100644
--- a/fork.c
+++ b/fork.c
@@ -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. */
diff --git a/pthread.h b/pthread.h
index dc3c608..8f6fdc5 100644
--- a/pthread.h
+++ b/pthread.h
@@ -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