diff --git a/ChangeLog b/ChangeLog index cc7830c53d..b6f7abd5c3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2002-12-30 Ulrich Drepper + + * malloc/thread-m.h (thread_atfork): Define using __register_atfork. + 2002-12-30 Roland McGrath * Rules (generated): Target removed. diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog index 6927282eba..16e26d8950 100644 --- a/linuxthreads/ChangeLog +++ b/linuxthreads/ChangeLog @@ -1,3 +1,44 @@ +2002-12-31 Jakub Jelinek + + * sysdeps/pthread/list.h: New file. + * sysdeps/unix/sysv/linux/jmp-unwind.c: New file. + * sysdeps/unix/sysv/linux/fork.c: New file. + * sysdeps/unix/sysv/linux/fork.h: New file. + * sysdeps/unix/sysv/linux/ia64/fork.h: New file. + * sysdeps/unix/sysv/linux/sparc/fork.h: New file. + * sysdeps/unix/sysv/linux/register-atfork.c: New file. + * sysdeps/unix/sysv/linux/unregister-atfork.c: New file. + * sysdeps/unix/sysv/linux/Makefile: New file. + * sysdeps/unix/sysv/linux/Versions: New file. + * ptlongjmp.c (pthread_cleanup_upto): Rename to... + (__pthread_cleanup_upto): ...this. Add targetframe argument, + use it instead of currentframe. No longer static. + (siglongjmp, longjmp): Remove pthread_cleanup_upto calls. + * internals.h (__pthread_cleanup_upto, __pthread_fork): New prototypes. + (struct pthread_functions): Add ptr_pthread_fork, + ptr_pthread_cleanup_upto. + * pthread.c (pthread_functions): Initialize ptr_pthread_fork and + ptr_pthread_cleanup_upto. + * ptfork.c: Include fork.h. + (struct handler_list, struct handler_list_block): Remove. + (pthread_atfork_lock, pthread_atfork_prepare, pthread_atfork_parent, + pthread_atfork_child): Remove. + (pthread_insert_list, __pthread_atfork, pthread_call_handlers): Remove. + (__pthread_fork): New function. + (__fork, __vfork): Call __libc_fork. + * Makefile (libpthread-routines): Add old_pthread_atfork. + (libpthread-nonshared): Add pthread_atfork. + (others): Depend on $(objpfx)libpthread_nonshared.a. + ($(objpfx)libpthread_nonshared.a): New rule. + (install): Depend on $(inst_libdir)/libpthread.so. + ($(inst_libdir)/libpthread.so, $(inst_libdir)/libpthread_nonshared.a): + New rules. + (tests): Depend on libpthread_nonshared.a too. + * old_pthread_atfork.c: New file. + * pthread_atfork.c: New file. + * Makeconfig (shared-thread-library): Include libpthread_nonshared.a + too. + 2002-12-30 Jakub Jelinek * forward.c: Make all functions available by default again. It diff --git a/linuxthreads/Makeconfig b/linuxthreads/Makeconfig index 4b1c0c3414..2dfd58c99e 100644 --- a/linuxthreads/Makeconfig +++ b/linuxthreads/Makeconfig @@ -3,7 +3,8 @@ have-thread-library = yes -shared-thread-library = $(common-objpfx)linuxthreads/libpthread.so +shared-thread-library = $(common-objpfx)linuxthreads/libpthread.so \ + $(common-objpfx)linuxthreads/libpthread_nonshared.a static-thread-library = $(common-objpfx)linuxthreads/libpthread.a bounded-thread-library = $(common-objpfx)linuxthreads/libpthread_b.a diff --git a/linuxthreads/Makefile b/linuxthreads/Makefile index a86aae7d53..9a6745fe17 100644 --- a/linuxthreads/Makefile +++ b/linuxthreads/Makefile @@ -46,12 +46,14 @@ libpthread-routines := attr cancel condvar join manager mutex ptfork \ ptw-lseek64 ptw-llseek ptw-msync ptw-nanosleep \ ptw-open ptw-open64 ptw-pause ptw-pread ptw-pread64 \ ptw-pwrite ptw-pwrite64 ptw-tcdrain ptw-wait \ - ptw-waitpid pt-system + ptw-waitpid pt-system old_pthread_atfork # Don't generate deps for calls with no sources. See sysdeps/unix/Makefile. omit-deps = $(unix-syscalls:%=ptw-%) libpthread-shared-only-routines = pt-allocrtsig +libpthread-nonshared = pthread_atfork + nodelete-yes = -Wl,--enable-new-dtags,-z,nodelete initfirst-yes = -Wl,--enable-new-dtags,-z,initfirst LDFLAGS-pthread.so = $(nodelete-$(have-z-nodelete)) \ @@ -65,6 +67,14 @@ CFLAGS-tst-cancel.c = -fno-inline -fno-inline-functions include ../Makeconfig ifeq ($(build-shared),yes) +others: $(objpfx)libpthread_nonshared.a +endif + +$(objpfx)libpthread_nonshared.a: $(addprefix $(objpfx),$(addsuffix .os,$(libpthread-nonshared))) + $(AR) $(ARFLAGS) $@ $^ + +ifeq ($(build-shared),yes) + extra-objs += crti.o crtn.o omit-deps += crti crtn @@ -92,6 +102,31 @@ endif include ../Rules +# What we install as libpthread.so for programs to link against is in fact a +# link script. It contains references for the various libraries we need. +# The libpthread.so object is not complete since some functions are only defined +# in libpthread_nonshared.a. +# We need to use absolute paths since otherwise local copies (if they exist) +# of the files are taken by the linker. +install: $(inst_libdir)/libpthread.so +$(inst_libdir)/libpthread.so: $(common-objpfx)format.lds \ + $(objpfx)libpthread.so$(libpthread.so-version) \ + $(inst_libdir)/$(patsubst %,$(libtype.oS),\ + $(libprefix)pthread) \ + $(+force) + (echo '/* GNU ld script';\ + echo ' Use the shared library, but some functions are only in';\ + echo ' the static library, so try that secondarily. */';\ + cat $<; \ + echo 'GROUP ( $(slibdir)/libpthread.so$(libpthread.so-version)' \ + '$(libdir)/$(patsubst %,$(libtype.oS),$(libprefix)pthread)'\ + ')' \ + ) > $@.new + mv -f $@.new $@ +$(inst_libdir)/libpthread_nonshared.a: $(objpfx)libpthread_nonshared.a + $(do-install) + + extra-B-pthread.so = -B$(common-objpfx)linuxthreads/ $(objpfx)libpthread.so: $(objpfx)crti.o $(objpfx)crtn.o $(objpfx)libpthread.so: +preinit += $(objpfx)crti.o @@ -154,14 +189,16 @@ $(objpfx)libpthread.so: $(libc-link.so) $(common-objpfx)libc_nonshared.a ifeq ($(build-shared),yes) $(addprefix $(objpfx), \ $(filter-out $(tests-static) $(tests-reverse) unload, \ - $(tests) $(test-srcs))): $(objpfx)libpthread.so + $(tests) $(test-srcs))): $(objpfx)libpthread.so \ + $(objpfx)libpthread_nonshared.a # $(objpfx)../libc.so is used instead of $(common-objpfx)libc.so, # since otherwise libpthread.so comes before libc.so when linking. $(addprefix $(objpfx), $(tests-reverse)): \ - $(objpfx)../libc.so $(objpfx)libpthread.so + $(objpfx)../libc.so $(objpfx)libpthread.so \ + $(objpfx)libpthread_nonshared.a $(addprefix $(objpfx),$(librt-tests)): $(common-objpfx)rt/librt.so $(objpfx)unload: $(common-objpfx)dlfcn/libdl.so -$(objpfx)unload.out: $(objpfx)libpthread.so +$(objpfx)unload.out: $(objpfx)libpthread.so $(objpfx)libpthread_nonshared.a else $(addprefix $(objpfx),$(tests) $(test-srcs)): $(objpfx)libpthread.a $(addprefix $(objpfx),$(librt-tests)): $(common-objpfx)rt/librt.a diff --git a/linuxthreads/internals.h b/linuxthreads/internals.h index 8c4de222b4..872bc5c047 100644 --- a/linuxthreads/internals.h +++ b/linuxthreads/internals.h @@ -463,6 +463,11 @@ extern int __libc_enable_asynccancel (void) attribute_hidden; extern void __libc_disable_asynccancel (int oldtype) internal_function attribute_hidden; +extern void __pthread_cleanup_upto (__jmp_buf target, + char *targetframe) attribute_hidden; +struct fork_block; +extern pid_t __pthread_fork (struct fork_block *b) attribute_hidden; + #if !defined NOT_IN_libc # define LIBC_CANCEL_ASYNC() \ __libc_enable_asynccancel () @@ -482,6 +487,7 @@ extern void __libc_disable_asynccancel (int oldtype) the thread functions. */ struct pthread_functions { + pid_t (*ptr_pthread_fork) (struct fork_block *); int (*ptr_pthread_attr_destroy) (pthread_attr_t *); int (*ptr___pthread_attr_init_2_0) (pthread_attr_t *); int (*ptr___pthread_attr_init_2_1) (pthread_attr_t *); @@ -519,6 +525,8 @@ struct pthread_functions int (*ptr_pthread_setcancelstate) (int, int *); int (*ptr_pthread_setcanceltype) (int, int *); void (*ptr_pthread_do_exit) (void *retval, char *currentframe); + void (*ptr_pthread_cleanup_upto) (__jmp_buf target, + char *targetframe); pthread_descr (*ptr_pthread_thread_self) (void); int (*ptr_pthread_internal_tsd_set) (int key, const void * pointer); void * (*ptr_pthread_internal_tsd_get) (int key); diff --git a/linuxthreads/old_pthread_atfork.c b/linuxthreads/old_pthread_atfork.c new file mode 100644 index 0000000000..768e6876c4 --- /dev/null +++ b/linuxthreads/old_pthread_atfork.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include + +#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_3) +# define __pthread_atfork __dyn_pthread_atfork +# include "pthread_atfork.c" +# undef __pthread_atfork +compat_symbol (libpthread, __dyn_pthread_atfork, pthread_atfork, GLIBC_2_0); +#endif diff --git a/linuxthreads/ptfork.c b/linuxthreads/ptfork.c index 564f8d7c75..195ffcd1b0 100644 --- a/linuxthreads/ptfork.c +++ b/linuxthreads/ptfork.c @@ -21,96 +21,71 @@ #include "pthread.h" #include "internals.h" #include +#include "fork.h" -struct handler_list { - void (*handler)(void); - struct handler_list * next; -}; +extern int __libc_fork (void); -static pthread_mutex_t pthread_atfork_lock = PTHREAD_MUTEX_INITIALIZER; -static struct handler_list * pthread_atfork_prepare = NULL; -static struct handler_list * pthread_atfork_parent = NULL; -static struct handler_list * pthread_atfork_child = NULL; - -static void pthread_insert_list(struct handler_list ** list, - void (*handler)(void), - struct handler_list * newlist, - int at_end) -{ - if (handler == NULL) return; - if (at_end) { - while(*list != NULL) list = &((*list)->next); - } - newlist->handler = handler; - newlist->next = *list; - *list = newlist; -} - -struct handler_list_block { - struct handler_list prepare, parent, child; -}; - -int __pthread_atfork(void (*prepare)(void), - void (*parent)(void), - void (*child)(void)) -{ - struct handler_list_block * block = - (struct handler_list_block *) malloc(sizeof(struct handler_list_block)); - if (block == NULL) return ENOMEM; - pthread_mutex_lock(&pthread_atfork_lock); - /* "prepare" handlers are called in LIFO */ - pthread_insert_list(&pthread_atfork_prepare, prepare, &block->prepare, 0); - /* "parent" handlers are called in FIFO */ - pthread_insert_list(&pthread_atfork_parent, parent, &block->parent, 1); - /* "child" handlers are called in FIFO */ - pthread_insert_list(&pthread_atfork_child, child, &block->child, 1); - pthread_mutex_unlock(&pthread_atfork_lock); - return 0; -} -strong_alias (__pthread_atfork, pthread_atfork) - -static inline void pthread_call_handlers(struct handler_list * list) -{ - for (/*nothing*/; list != NULL; list = list->next) (list->handler)(); -} - -extern int __libc_fork(void); - -pid_t __fork(void) +pid_t __pthread_fork (struct fork_block *b) { pid_t pid; + list_t *runp; - pthread_mutex_lock(&pthread_atfork_lock); + __libc_lock_lock (b->lock); + + /* Run all the registered preparation handlers. In reverse order. */ + list_for_each_prev (runp, &b->prepare_list) + { + struct fork_handler *curp; + curp = list_entry (runp, struct fork_handler, list); + curp->handler (); + } - pthread_call_handlers(pthread_atfork_prepare); __pthread_once_fork_prepare(); __flockfilelist(); - pid = __libc_fork(); + pid = ARCH_FORK (); if (pid == 0) { __pthread_reset_main_thread(); __fresetlockfiles(); __pthread_once_fork_child(); - pthread_call_handlers(pthread_atfork_child); - pthread_mutex_init(&pthread_atfork_lock, NULL); + /* Run the handlers registered for the child. */ + list_for_each (runp, &b->child_list) + { + struct fork_handler *curp; + curp = list_entry (runp, struct fork_handler, list); + curp->handler (); + } + + __libc_lock_init (b->lock); } else { __funlockfilelist(); __pthread_once_fork_parent(); - pthread_call_handlers(pthread_atfork_parent); - pthread_mutex_unlock(&pthread_atfork_lock); + /* Run the handlers registered for the parent. */ + list_for_each (runp, &b->parent_list) + { + struct fork_handler *curp; + curp = list_entry (runp, struct fork_handler, list); + curp->handler (); + } + + __libc_lock_unlock (b->lock); } return pid; } +pid_t __fork (void) +{ + return __libc_fork (); +} weak_alias (__fork, fork); pid_t __vfork(void) { - return __fork(); + return __libc_fork (); } weak_alias (__vfork, vfork); diff --git a/linuxthreads/pthread.c b/linuxthreads/pthread.c index 15de7e610f..444c0a0ed2 100644 --- a/linuxthreads/pthread.c +++ b/linuxthreads/pthread.c @@ -238,6 +238,7 @@ static struct pthread_functions pthread_functions = .ptr_pthread_internal_tsd_get = __pthread_internal_tsd_get, .ptr_pthread_internal_tsd_address = __pthread_internal_tsd_address, #endif + .ptr_pthread_fork = __pthread_fork, .ptr_pthread_attr_destroy = __pthread_attr_destroy, #if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1) .ptr___pthread_attr_init_2_0 = __pthread_attr_init_2_0, @@ -273,7 +274,8 @@ static struct pthread_functions pthread_functions = .ptr_pthread_setcancelstate = __pthread_setcancelstate, .ptr_pthread_setcanceltype = __pthread_setcanceltype, .ptr_pthread_do_exit = __pthread_do_exit, - .ptr_pthread_thread_self = __pthread_thread_self + .ptr_pthread_thread_self = __pthread_thread_self, + .ptr_pthread_cleanup_upto = __pthread_cleanup_upto }; # define ptr_pthread_functions &pthread_functions #else diff --git a/linuxthreads/pthread_atfork.c b/linuxthreads/pthread_atfork.c new file mode 100644 index 0000000000..dabb26a726 --- /dev/null +++ b/linuxthreads/pthread_atfork.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "internals.h" +#include + +/* This is defined by newer gcc version unique for each module. */ +extern void *__dso_handle __attribute__ ((__weak__)); + + +/* Hide the symbol so that no definition but the one locally in the + executable or DSO is used. */ +int +#ifndef __pthread_atfork +/* Don't mark the compatibility function as hidden. */ +attribute_hidden +#endif +__pthread_atfork (prepare, parent, child) + void (*prepare) (void); + void (*parent) (void); + void (*child) (void); +{ + return __register_atfork (prepare, parent, child, + &__dso_handle == NULL ? NULL : __dso_handle); +} +#ifndef __pthread_atfork +extern int pthread_atfork (void (*prepare) (void), void (*parent) (void), + void (*child) (void)) attribute_hidden; +strong_alias (__pthread_atfork, pthread_atfork) +#endif diff --git a/linuxthreads/ptlongjmp.c b/linuxthreads/ptlongjmp.c index 18592548ed..ece553141f 100644 --- a/linuxthreads/ptlongjmp.c +++ b/linuxthreads/ptlongjmp.c @@ -27,24 +27,23 @@ extern void __libc_longjmp (sigjmp_buf env, int val) __attribute__ ((noreturn)); -static void pthread_cleanup_upto(__jmp_buf target) +void __pthread_cleanup_upto (__jmp_buf target, char *targetframe) { pthread_descr self = thread_self(); struct _pthread_cleanup_buffer * c; - char *currentframe = CURRENT_STACK_FRAME; for (c = THREAD_GETMEM(self, p_cleanup); c != NULL && _JMPBUF_UNWINDS(target, c); c = c->__prev) { #if _STACK_GROWS_DOWN - if ((char *) c <= currentframe) + if ((char *) c <= targetframe) { c = NULL; break; } #elif _STACK_GROWS_UP - if ((char *) c >= currentframe) + if ((char *) c >= targetframe) { c = NULL; break; @@ -60,14 +59,12 @@ static void pthread_cleanup_upto(__jmp_buf target) THREAD_SETMEM(self, p_in_sighandler, NULL); } -void siglongjmp(sigjmp_buf env, int val) +void siglongjmp (sigjmp_buf env, int val) { - pthread_cleanup_upto(env->__jmpbuf); - __libc_siglongjmp(env, val); + __libc_siglongjmp (env, val); } -void longjmp(jmp_buf env, int val) +void longjmp (jmp_buf env, int val) { - pthread_cleanup_upto(env->__jmpbuf); - __libc_longjmp(env, val); + __libc_longjmp (env, val); } diff --git a/linuxthreads/sysdeps/pthread/list.h b/linuxthreads/sysdeps/pthread/list.h new file mode 100644 index 0000000000..1d6a4cfa65 --- /dev/null +++ b/linuxthreads/sysdeps/pthread/list.h @@ -0,0 +1,116 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LIST_H +#define _LIST_H 1 + +#include + +/* The definitions of this file are adopted from those which can be + found in the Linux kernel headers to enable people familiar with + the latter find their way in these sources as well. */ + + +/* Basic type for the double-link list. */ +typedef struct list_head +{ + struct list_head *next; + struct list_head *prev; +} list_t; + + +/* Define a variable with the head and tail of the list. */ +#define LIST_HEAD(name) \ + list_t name = { &(name), &(name) } + +/* Initialize a new list head. */ +#define INIT_LIST_HEAD(ptr) \ + (ptr)->next = (ptr)->prev = (ptr) + + +/* Add new element at the head of the list. */ +static inline void +list_add (list_t *newp, list_t *head) +{ + head->next->prev = newp; + newp->next = head->next; + newp->prev = head; + head->next = newp; +} + + +/* Add new element at the tail of the list. */ +static inline void +list_add_tail (list_t *newp, list_t *head) +{ + head->prev->next = newp; + newp->next = head; + newp->prev = head->prev; + head->prev = newp; +} + + +/* Remove element from list. */ +static inline void +list_del (list_t *elem) +{ + elem->next->prev = elem->prev; + elem->prev->next = elem->next; +} + + +/* Join two lists. */ +static inline void +list_splice (list_t *add, list_t *head) +{ + /* Do nothing if the list which gets added is empty. */ + if (add != add->next) + { + add->next->prev = head; + add->prev->next = head->next; + head->next->prev = add->prev; + head->next = add->next; + } +} + + +/* Get typed element from list at a given position. */ +#define list_entry(ptr, type, member) \ + ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member))) + + + +/* Iterate forward over the elements of the list. */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + + +/* Iterate forward over the elements of the list. */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); pos = pos->prev) + + +/* Iterate backwards over the elements list. The list elements can be + removed from the list while doing this. */ +#define list_for_each_prev_safe(pos, p, head) \ + for (pos = (head)->prev, p = pos->prev; \ + pos != (head); \ + pos = p, p = pos->prev) + +#endif /* list.h */ diff --git a/linuxthreads/sysdeps/unix/sysv/linux/Makefile b/linuxthreads/sysdeps/unix/sysv/linux/Makefile new file mode 100644 index 0000000000..38c6cbc1af --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),linuxthreads) +sysdep_routines += register-atfork unregister-atfork +endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/Versions b/linuxthreads/sysdeps/unix/sysv/linux/Versions new file mode 100644 index 0000000000..6cd3dbe372 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/Versions @@ -0,0 +1,5 @@ +libc { + GLIBC_2.3.2 { + __register_atfork; + } +} diff --git a/linuxthreads/sysdeps/unix/sysv/linux/fork.c b/linuxthreads/sysdeps/unix/sysv/linux/fork.c new file mode 100644 index 0000000000..c519fa0677 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/fork.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include "fork.h" +#include + +weak_extern (__pthread_fork); + +struct fork_block __fork_block = +{ + .lock = PTHREAD_MUTEX_INITIALIZER, + .prepare_list = { &__fork_block.prepare_list, &__fork_block.prepare_list }, + .parent_list = { &__fork_block.parent_list, &__fork_block.parent_list }, + .child_list = { &__fork_block.child_list, &__fork_block.child_list } +}; + +pid_t +__libc_fork (void) +{ + return __libc_maybe_call2 (pthread_fork, (&__fork_block), ARCH_FORK ()); +} +weak_alias (__libc_fork, __fork) +weak_alias (__libc_fork, fork) diff --git a/linuxthreads/sysdeps/unix/sysv/linux/fork.h b/linuxthreads/sysdeps/unix/sysv/linux/fork.h new file mode 100644 index 0000000000..e84119a2ef --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/fork.h @@ -0,0 +1,59 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include + +struct fork_block +{ + /* Lock to protect handling of fork handlers. */ + __libc_lock_define (, lock); + + /* Lists of registered fork handlers. */ + list_t prepare_list; + list_t parent_list; + list_t child_list; +}; + +extern struct fork_block __fork_block attribute_hidden; + +/* Elements of the fork handler lists. */ +struct fork_handler +{ + list_t list; + void (*handler) (void); + void *dso_handle; +}; + + +/* Function to call to unregister fork handlers. */ +extern void __unregister_atfork (void *dso_handle) attribute_hidden; +#define UNREGISTER_ATFORK(dso_handle) __unregister_atfork (dso_handle) + + +/* C library side function to register new fork handlers. */ +extern int __register_atfork (void (*__prepare) (void), + void (*__parent) (void), + void (*__child) (void), + void *dso_handle); + +#ifndef ARCH_FORK +# define ARCH_FORK() INLINE_SYSCALL (fork, 0) +#endif diff --git a/linuxthreads/sysdeps/unix/sysv/linux/ia64/fork.h b/linuxthreads/sysdeps/unix/sysv/linux/ia64/fork.h new file mode 100644 index 0000000000..30a0cc1918 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/ia64/fork.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include + +#define ARCH_FORK() INLINE_SYSCALL (clone, 2, SIGCHLD, 0) + +#include_next diff --git a/linuxthreads/sysdeps/unix/sysv/linux/jmp-unwind.c b/linuxthreads/sysdeps/unix/sysv/linux/jmp-unwind.c new file mode 100644 index 0000000000..37cc4c2c0b --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/jmp-unwind.c @@ -0,0 +1,32 @@ +/* _longjmp_unwind -- Clean up stack frames unwound by longjmp. + Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include + +weak_extern (__pthread_cleanup_upto); + +void +_longjmp_unwind (jmp_buf env, int val) +{ + __libc_maybe_call2 (pthread_cleanup_upto, + (env->__jmpbuf, __builtin_frame_address (0)), + (void) 0); +} diff --git a/linuxthreads/sysdeps/unix/sysv/linux/register-atfork.c b/linuxthreads/sysdeps/unix/sysv/linux/register-atfork.c new file mode 100644 index 0000000000..2dce262a38 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/register-atfork.c @@ -0,0 +1,87 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include "fork.h" + + +int +__register_atfork (prepare, parent, child, dso_handle) + void (*prepare) (void); + void (*parent) (void); + void (*child) (void); + void *dso_handle; +{ + struct fork_handler *new_prepare = NULL; + struct fork_handler *new_parent = NULL; + struct fork_handler *new_child = NULL; + + if (prepare != NULL) + { + new_prepare = (struct fork_handler *) malloc (sizeof (*new_prepare)); + if (new_prepare == NULL) + goto out1; + + new_prepare->handler = prepare; + new_prepare->dso_handle = dso_handle; + } + + if (parent != NULL) + { + new_parent = (struct fork_handler *) malloc (sizeof (*new_parent)); + if (new_parent == NULL) + goto out2; + + new_parent->handler = parent; + new_parent->dso_handle = dso_handle; + } + + if (child != NULL) + { + new_child = (struct fork_handler *) malloc (sizeof (*new_child)); + if (new_child == NULL) + { + free (new_parent); + out2: + free (new_prepare); + out1: + return errno; + } + + new_child->handler = child; + new_child->dso_handle = dso_handle; + } + + /* Get the lock to not conflict with running forks. */ + __libc_lock_lock (__fork_block.lock); + + /* Now that we have all the handlers allocate enqueue them. */ + if (new_prepare != NULL) + list_add_tail (&new_prepare->list, &__fork_block.prepare_list); + if (new_parent != NULL) + list_add_tail (&new_parent->list, &__fork_block.parent_list); + if (new_child != NULL) + list_add_tail (&new_child->list, &__fork_block.child_list); + + /* Release the lock. */ + __libc_lock_unlock (__fork_block.lock); + + return 0; +} diff --git a/linuxthreads/sysdeps/unix/sysv/linux/sparc/fork.h b/linuxthreads/sysdeps/unix/sysv/linux/sparc/fork.h new file mode 100644 index 0000000000..793cb1d5f9 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/sparc/fork.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include + +#define ARCH_FORK() \ +({ \ + register long __o0 __asm__ ("o0"); \ + register long __o1 __asm__ ("o1"); \ + register long __g1 __asm__ ("g1") = __NR_fork; \ + __asm __volatile (__SYSCALL_STRING \ + : "=r" (__g1), "=r" (__o0), "=r" (__o1) \ + : "0" (__g1) \ + : __SYSCALL_CLOBBERS); \ + __o0 == -1 ? __o0 : (__o0 & (__o1 - 1)); \ +}) + +#include_next diff --git a/linuxthreads/sysdeps/unix/sysv/linux/unregister-atfork.c b/linuxthreads/sysdeps/unix/sysv/linux/unregister-atfork.c new file mode 100644 index 0000000000..dad273fdf5 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/unregister-atfork.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include "fork.h" + + +void +__unregister_atfork (dso_handle) + void *dso_handle; +{ + /* Get the lock to not conflict with running forks. */ + __libc_lock_lock (__fork_block.lock); + + list_t *runp; + list_t *prevp; + + list_for_each_prev_safe (runp, prevp, &__fork_block.prepare_list) + if (list_entry (runp, struct fork_handler, list)->dso_handle == dso_handle) + list_del (runp); + + list_for_each_prev_safe (runp, prevp, &__fork_block.parent_list) + if (list_entry (runp, struct fork_handler, list)->dso_handle == dso_handle) + list_del (runp); + + list_for_each_prev_safe (runp, prevp, &__fork_block.child_list) + if (list_entry (runp, struct fork_handler, list)->dso_handle == dso_handle) + list_del (runp); + + /* Release the lock. */ + __libc_lock_unlock (__fork_block.lock); +} diff --git a/malloc/thread-m.h b/malloc/thread-m.h index 49db784c52..d3352d1fe5 100644 --- a/malloc/thread-m.h +++ b/malloc/thread-m.h @@ -72,8 +72,14 @@ __libc_lock_define (typedef, mutex_t) #endif +/* This is defined by newer gcc version unique for each module. */ +extern void *__dso_handle __attribute__ ((__weak__)); + +#include + #define thread_atfork(prepare, parent, child) \ - (__pthread_atfork != NULL ? __pthread_atfork(prepare, parent, child) : 0) + __register_atfork (prepare, parent, child, \ + &__dso_handle == NULL ? NULL : __dso_handle) #elif defined(MUTEX_INITIALIZER) /* Assume hurd, with cthreads */ diff --git a/nptl/ChangeLog b/nptl/ChangeLog index 3d527a959a..35ef11fba9 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -1,5 +1,8 @@ 2002-12-30 Ulrich Drepper + * sysdeps/pthread/pt-initfini.c (call_initialize_minimal): Mark + __pthread_initialize_minimal as hidden. + * init.c (__pthread_initialize_minimal_internal): Don't mark as constructor. diff --git a/nptl/sysdeps/pthread/pt-initfini.c b/nptl/sysdeps/pthread/pt-initfini.c index 55d9f31562..7aa734d020 100644 --- a/nptl/sysdeps/pthread/pt-initfini.c +++ b/nptl/sysdeps/pthread/pt-initfini.c @@ -1,5 +1,5 @@ /* Special .init and .fini section support. Linuxthread version. - Copyright (C) 1995, 1996, 1997, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1995,1996,1997,2000,2001,2002 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it @@ -65,7 +65,8 @@ asm ("\n/*@_init_PROLOG_BEGINS*/"); static void call_initialize_minimal (void) { - extern void __pthread_initialize_minimal (void); + extern void __pthread_initialize_minimal (void) + __attribute ((visibility ("hidden"))); __pthread_initialize_minimal (); }