Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Faylor <me@cgf.cx>2001-04-13 19:28:20 +0400
committerChristopher Faylor <me@cgf.cx>2001-04-13 19:28:20 +0400
commit39b6859a28b8b50d73fe6ae080ea42f4ef1bdea3 (patch)
tree6e6cc0afd7868c2a935f16c4e10a3d20ebf532b3 /winsup/cygwin/thread.cc
parente61cead397205b61dafed0d725cf9dcd89aead76 (diff)
* fork.cc (fork_child): Call the __pthread_atforkchild function.
(fork_parent): Call the __pthread_atforkparent function. * cygwin.din: Export pthread_atfork. * thread.h (callback): New class. (MTinterface): Use it. * thread.cc (__pthread_atforkprepare): New function. (__pthread_atforkparent): New function. (__pthread_atforkchild): New function. (__pthread_atfork): New function. * pthread.cc (pthread_atfork): New function.
Diffstat (limited to 'winsup/cygwin/thread.cc')
-rw-r--r--winsup/cygwin/thread.cc118
1 files changed, 118 insertions, 0 deletions
diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc
index e870c3131..1bcfd4e4d 100644
--- a/winsup/cygwin/thread.cc
+++ b/winsup/cygwin/thread.cc
@@ -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)
{