X-Git-Url: https://git.saurik.com/apple/libc.git/blobdiff_plain/5b2abdfbf4211b6592cdd02b9507555a0ecbb04b..fbd86d4cc20b02a10edcca92fb7ae0a143e63cc4:/threads/cthreads.c?ds=sidebyside diff --git a/threads/cthreads.c b/threads/cthreads.c index bad453f..0aca02d 100644 --- a/threads/cthreads.c +++ b/threads/cthreads.c @@ -3,19 +3,20 @@ * * @APPLE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ @@ -29,10 +30,11 @@ * fixed kernel cache set up of cproc info * */ +#include "pthread_internals.h" #include +#include #include "cthreads.h" #include "cthread_internals.h" -#include "pthread_internals.h" /* * C Threads imports: */ @@ -41,6 +43,9 @@ extern thread_port_t cproc_create(); extern void mig_init(); extern void _pthread_set_self(pthread_t); +extern void pthread_workqueue_atfork_prepare(void); +extern void pthread_workqueue_atfork_parent(void); +extern void pthread_workqueue_atfork_child(void); /* * Mach imports: */ @@ -61,7 +66,7 @@ extern void _longjmp(jmp_buf env, int val); #ifdef CTHREADS_DEBUG int cthread_debug = FALSE; -#endif CTHREADS_DEBUG +#endif /* CTHREADS_DEBUG */ /* * Routines for supporting fork() of multi-threaded programs. @@ -70,12 +75,42 @@ int cthread_debug = FALSE; extern void _malloc_fork_prepare(), _malloc_fork_parent(); extern void _malloc_fork_child(); +extern void fork_mach_init(); extern void _cproc_fork_child(), _stack_fork_child(); extern void _lu_fork_child(void); -extern void _pthread_fork_child(void); +extern void _asl_fork_child(void); +extern void _pthread_fork_child(pthread_t); +extern void _notify_fork_child(void); static pthread_t psaved_self = 0; static pthread_lock_t psaved_self_global_lock = LOCK_INITIALIZER; +static pthread_lock_t pthread_atfork_lock = LOCK_INITIALIZER; +struct pthread_atfork_entry { + TAILQ_ENTRY(pthread_atfork_entry) qentry; + void (*prepare)(void); + void (*parent)(void); + void (*child)(void); +}; +static TAILQ_HEAD(pthread_atfork_queue_head, pthread_atfork_entry) pthread_atfork_queue = TAILQ_HEAD_INITIALIZER(pthread_atfork_queue); + +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) +{ + struct pthread_atfork_entry *e; + + e = malloc(sizeof(struct pthread_atfork_entry)); + if (e == NULL) + return (ENOMEM); + + e->prepare = prepare; + e->parent = parent; + e->child = child; + + _spin_lock(&pthread_atfork_lock); + TAILQ_INSERT_TAIL(&pthread_atfork_queue, e, qentry); + _spin_unlock(&pthread_atfork_lock); + + return 0; +} void _cthread_fork_prepare() /* @@ -85,10 +120,25 @@ void _cthread_fork_prepare() * state in the child, which comes up with only the forking thread running. */ { - _spin_lock(&psaved_self_global_lock); - psaved_self = pthread_self(); - _spin_lock(&psaved_self->lock); + struct pthread_atfork_entry *e; + + _spin_lock(&pthread_atfork_lock); +#ifdef TAILQ_FOREACH_REVERSE_LEGACY_ORDER + TAILQ_FOREACH_REVERSE(e, &pthread_atfork_queue, qentry, pthread_atfork_queue_head) +#else /* !TAILQ_FOREACH_REVERSE_LEGACY_ORDER */ + TAILQ_FOREACH_REVERSE(e, &pthread_atfork_queue, pthread_atfork_queue_head, qentry) +#endif /* TAILQ_FOREACH_REVERSE_LEGACY_ORDER */ + { + if (e->prepare != NULL) + e->prepare(); + } + + _spin_lock(&psaved_self_global_lock); + psaved_self = pthread_self(); + _spin_lock(&psaved_self->lock); _malloc_fork_prepare(); + + pthread_workqueue_atfork_prepare(); } void _cthread_fork_parent() @@ -97,10 +147,19 @@ void _cthread_fork_parent() * Releases locks acquired by cthread_fork_prepare(). */ { + struct pthread_atfork_entry *e; + _malloc_fork_parent(); _spin_unlock(&psaved_self->lock); _spin_unlock(&psaved_self_global_lock); + TAILQ_FOREACH(e, &pthread_atfork_queue, qentry) { + if (e->parent != NULL) + e->parent(); + } + _spin_unlock(&pthread_atfork_lock); + + pthread_workqueue_atfork_parent(); } void _cthread_fork_child() @@ -108,34 +167,44 @@ void _cthread_fork_child() * Called in the child process after a fork syscall. Releases locks acquired * by cthread_fork_prepare(). Deallocates cthread data structures which * described other threads in our parent. Makes this thread the main thread. - * - * The mach_init() routine must be called in the child before this routine. */ { pthread_t p = psaved_self; + struct pthread_atfork_entry *e; _pthread_set_self(p); _spin_unlock(&psaved_self_global_lock); mig_fork_child(); _malloc_fork_child(); p->kernel_thread = mach_thread_self(); - p->reply_port = MACH_PORT_NULL; + p->reply_port = mach_reply_port(); p->mutexes = NULL; - p->cleanup_stack = NULL; + p->__cleanup_stack = NULL; p->death = MACH_PORT_NULL; p->joiner = NULL; p->detached |= _PTHREAD_CREATE_PARENT; _spin_unlock(&p->lock); - _cproc_fork_child(); + fork_mach_init(); + _pthread_fork_child(p); - _lu_fork_child(); + _cproc_fork_child(); - _pthread_fork_child(); + _lu_fork_child(); + _asl_fork_child(); + _notify_fork_child(); __is_threaded = 0; mig_init(1); /* enable multi-threaded mig interfaces */ + + pthread_workqueue_atfork_child(); + + TAILQ_FOREACH(e, &pthread_atfork_queue, qentry) { + if (e->child != NULL) + e->child(); + } + LOCK_INIT(pthread_atfork_lock); }