Index: fork.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/fork.cc,v
retrieving revision 1.42
diff -u -p -r1.42 fork.cc
--- fork.cc	2001/03/18 03:34:05	1.42
+++ fork.cc	2001/04/13 12:35:02
@@ -640,6 +640,9 @@ fork ()
       return -1;
     }
 
+  /* call the pthread_atfork prepare functions */
+  __pthread_atforkprepare();
+
   void *esp;
   __asm ("movl %%esp,%0": "=r" (esp));
 
@@ -650,9 +653,15 @@ fork ()
   int res = setjmp (ch.jmp);
 
   if (res)
-    res = fork_child (grouped.hParent, grouped.first_dll, grouped.load_dlls);
+    {
+      res = fork_child (grouped.hParent, grouped.first_dll, grouped.load_dlls);
+      __pthread_atforkchild();
+    }
   else
-    res = fork_parent (esp, grouped.hParent, grouped.first_dll, grouped.load_dlls, ch);
+    {
+      res = fork_parent (esp, grouped.hParent, grouped.first_dll, grouped.load_dlls, ch);
+      __pthread_atforkparent();
+    }
 
   MALLOC_CHECK;
   syscall_printf ("%d = fork()", res);
Index: thread.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/thread.h,v
retrieving revision 1.15
diff -u -p -r1.15 thread.h
--- thread.h	2001/04/12 04:04:53	1.15
+++ thread.h	2001/04/13 12:35:02
@@ -317,6 +317,13 @@ public:
    ~semaphore ();
 };
 
+class callback
+{
+public:
+  void (*cb)(void);
+  class callback * next;
+};
+
 class MTinterface
 {
 public:
@@ -333,14 +340,23 @@ public:
   pthread mainthread;
 
   pthread_key_destructor_list destructors;
+  callback *pthread_prepare;
+  callback *pthread_child;
+  callback *pthread_parent;
 
   void Init (int);
 
-    MTinterface ():reent_index (0), indexallocated (0)
+    MTinterface ():reent_index (0), indexallocated (0) 
   {
+    pthread_prepare = NULL;
+    pthread_child   = NULL;
+    pthread_parent  = NULL;
   }
 };
 
+void __pthread_atforkprepare(void);
+void __pthread_atforkparent(void);
+void __pthread_atforkchild(void);
 
 extern "C"
 {
@@ -350,6 +366,7 @@ void *thread_init_wrapper (void *);
 int __pthread_create (pthread_t * thread, const pthread_attr_t * attr,
 		      void *(*start_routine) (void *), void *arg);
 int __pthread_once (pthread_once_t *, void (*)(void));
+int __pthread_atfork(void (*)(void), void (*)(void), void (*)(void));
 
 int __pthread_attr_init (pthread_attr_t * attr);
 int __pthread_attr_destroy (pthread_attr_t * attr);
Index: cygwin.din
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/cygwin.din,v
retrieving revision 1.25
diff -u -p -r1.25 cygwin.din
--- cygwin.din	2001/04/12 04:04:53	1.25
+++ cygwin.din	2001/04/13 12:35:05
@@ -1076,6 +1076,7 @@ cygwin_attach_handle_to_fd
 cygwin32_attach_handle_to_fd = cygwin_attach_handle_to_fd
 cygwin_internal
 cygwin32_internal = cygwin_internal
+pthread_atfork
 pthread_attr_destroy
 pthread_attr_getdetachstate
 pthread_attr_getinheritsched
Index: thread.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/thread.cc,v
retrieving revision 1.22
diff -u -p -r1.22 thread.cc
--- thread.cc	2001/04/12 04:04:53	1.22
+++ thread.cc	2001/04/13 12:35:07
@@ -935,6 +935,124 @@ __pthread_testcancel (void)
    * does something*/
 }
 
+/*
+ * Races in pthread_atfork:
+ * We are race safe in that any additions to the lists are made via 
+ * InterlockedExchangePointer.
+ * However, if the user application doesn't perform syncronisation of some sort
+ * It's not guaranteed that a near simultaneous call to pthread_atfork and fork 
+ * will result in the new atfork handlers being calls.
+ * More rigorous internal syncronisation isn't needed as the user program isn't 
+ * guaranteeing their own state. 
+ *
+ * as far as multiple calls to pthread_atfork, the worst case is simultaneous calls
+ * will result in an indeterminate order for parent and child calls (what gets inserted
+ * first isn't guaranteed.)
+ *
+ * There is one potential race... Does the result of InterlockedExchangePointer 
+ * get committed to the return location _before_ any context switches can occur?
+ * If yes, we're safe, if no, we're not.
+ */
+void
+__pthread_atforkprepare(void)
+{
+  callback *cb=MT_INTERFACE->pthread_prepare;
+  while (cb)
+    {
+      cb->cb();
+      cb=cb->next;
+    }
+}
+
+void 
+__pthread_atforkparent(void)
+{
+  callback *cb=MT_INTERFACE->pthread_parent;
+  while (cb)
+    {
+      cb->cb();
+      cb=cb->next;
+    }
+}
+
+void
+__pthread_atforkchild(void)
+{
+  callback *cb=MT_INTERFACE->pthread_child;
+  while (cb)
+    {
+      cb->cb();
+      cb=cb->next;
+    }
+}
+
+/* FIXME: implement InterlockExchangePointer and get rid of the silly typecasts below
+ */
+#define InterlockedExchangePointer InterlockedExchange
+
+/* Register a set of functions to run before and after fork. 
+ * prepare calls are called in LI-FC order.
+ * parent and child calls are called in FI-FC order.
+ */
+int
+__pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
+{
+  callback * prepcb=NULL, * parentcb=NULL, * childcb=NULL;
+  if (prepare)
+    {
+      prepcb = new callback;
+      if (!prepcb)
+	return ENOMEM;
+    }
+  if (parent)
+    {
+      parentcb = new callback;
+      if (!parentcb)
+	{
+	  if (prepcb)
+	    delete prepcb;
+	  return ENOMEM;
+	}
+    }
+  if (child)
+    {
+      childcb = new callback;
+      if (!childcb)
+	{
+	  if (prepcb)
+	    delete prepcb;
+	  if (parentcb)
+	    delete parentcb;
+	  return ENOMEM;
+	}
+    }
+
+  if (prepcb)
+  {
+    prepcb->cb = prepare;
+    prepcb->next=(callback *)InterlockedExchangePointer((LONG *) &MT_INTERFACE->pthread_prepare, (long int) prepcb);
+  }
+  if (parentcb)
+  {
+    parentcb->cb = parent;
+    callback ** t = &MT_INTERFACE->pthread_parent;
+    while (*t)
+      t = &(*t)->next;
+    /* t = pointer to last next in the list */
+    parentcb->next=(callback *)InterlockedExchangePointer((LONG *)t, (long int) parentcb);
+  }
+  if (childcb)
+  {
+    childcb->cb = child;
+    callback ** t = &MT_INTERFACE->pthread_child;
+    while (*t)
+      t = &(*t)->next;
+    /* t = pointer to last next in the list */
+    childcb->next=(callback *)InterlockedExchangePointer((LONG *)t, (long int) childcb);
+  }
+  return 0;
+}
+
 int
 __pthread_attr_init (pthread_attr_t * attr)
 {
Index: pthread.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/pthread.cc,v
retrieving revision 1.8
diff -u -p -r1.8 pthread.cc
--- pthread.cc	2001/04/12 04:04:53	1.8
+++ pthread.cc	2001/04/13 12:35:07
@@ -30,6 +30,12 @@ pthread_once (pthread_once_t * once_cont
 }
 
 int
+pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
+{
+  return __pthread_atfork(prepare, parent, child);
+}
+
+int
 pthread_attr_init (pthread_attr_t * attr)
 {
   return __pthread_attr_init (attr);
