diff options
author | Christopher Faylor <me@cgf.cx> | 2001-04-13 15:28:20 +0000 |
---|---|---|
committer | Christopher Faylor <me@cgf.cx> | 2001-04-13 15:28:20 +0000 |
commit | 39b6859a28b8b50d73fe6ae080ea42f4ef1bdea3 (patch) | |
tree | 6e6cc0afd7868c2a935f16c4e10a3d20ebf532b3 /winsup | |
parent | e61cead397205b61dafed0d725cf9dcd89aead76 (diff) | |
download | newlib-39b6859a28b8b50d73fe6ae080ea42f4ef1bdea3.zip newlib-39b6859a28b8b50d73fe6ae080ea42f4ef1bdea3.tar.gz newlib-39b6859a28b8b50d73fe6ae080ea42f4ef1bdea3.tar.bz2 |
* 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')
-rw-r--r-- | winsup/cygwin/ChangeLog | 13 | ||||
-rw-r--r-- | winsup/cygwin/cygwin.din | 1 | ||||
-rw-r--r-- | winsup/cygwin/fhandler.cc | 5 | ||||
-rw-r--r-- | winsup/cygwin/fork.cc | 5 | ||||
-rw-r--r-- | winsup/cygwin/pthread.cc | 6 | ||||
-rw-r--r-- | winsup/cygwin/thread.cc | 118 | ||||
-rw-r--r-- | winsup/cygwin/thread.h | 19 |
7 files changed, 163 insertions, 4 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index f94ec6e..451a0c9 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,16 @@ +Fri Apr 13 2001 Robert Collins <rbtcollins@hotmail.com> + + * 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. + Fri Apr 13 9:52:00 2001 Corinna Vinschen <corinna@vinschen.de> * path.cc (add_ext_from_sym): New define evaluating `known'suffix'. diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index a94af5e..285f724 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -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 diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index ff9a9df..df2fd22 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -370,9 +370,8 @@ fhandler_base::open (int flags, mode_t mode) file_attributes, 0); - syscall_printf ("%d = CreateFileA (%s, %p, %p, %p, %p, %p, 0)", - x, - get_win32_name (), access_, shared, + syscall_printf ("%p = CreateFileA (%s, %p, %p, %p, %p, %p, 0)", + x, get_win32_name (), access_, shared, &sec_none, creation_distribution, file_attributes); diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index 6d6f10b..de85c1d 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -307,6 +307,7 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls) /* Initialize signal/process handling */ sigproc_init (); + __pthread_atforkchild(); cygbench ("fork-child"); return 0; } @@ -597,6 +598,7 @@ out: ForceCloseHandle (forker_finished); forker_finished = NULL; pi.hThread = NULL; + __pthread_atforkparent(); return forked->pid; @@ -640,6 +642,9 @@ fork () return -1; } + /* call the pthread_atfork prepare functions */ + __pthread_atforkprepare(); + void *esp; __asm ("movl %%esp,%0": "=r" (esp)); diff --git a/winsup/cygwin/pthread.cc b/winsup/cygwin/pthread.cc index c9f0bb2..74cce7c 100644 --- a/winsup/cygwin/pthread.cc +++ b/winsup/cygwin/pthread.cc @@ -30,6 +30,12 @@ pthread_once (pthread_once_t * once_control, void (*init_routine) (void)) } 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); diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index e870c31..1bcfd4e 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) { diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h index 00c10b2..2b6e7d7 100644 --- a/winsup/cygwin/thread.h +++ b/winsup/cygwin/thread.h @@ -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); |