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  | 
