2002-12-30  Ulrich Drepper  <drepper@redhat.com>

	* malloc/thread-m.h (thread_atfork): Define using __register_atfork.
This commit is contained in:
Ulrich Drepper 2002-12-31 08:00:19 +00:00
parent 89d6e44459
commit 416d2de60b
23 changed files with 679 additions and 81 deletions

View File

@ -1,3 +1,7 @@
2002-12-30 Ulrich Drepper <drepper@redhat.com>
* malloc/thread-m.h (thread_atfork): Define using __register_atfork.
2002-12-30 Roland McGrath <roland@redhat.com> 2002-12-30 Roland McGrath <roland@redhat.com>
* Rules (generated): Target removed. * Rules (generated): Target removed.

View File

@ -1,3 +1,44 @@
2002-12-31 Jakub Jelinek <jakub@redhat.com>
* 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 <jakub@redhat.com> 2002-12-30 Jakub Jelinek <jakub@redhat.com>
* forward.c: Make all functions available by default again. It * forward.c: Make all functions available by default again. It

View File

@ -3,7 +3,8 @@
have-thread-library = yes 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 static-thread-library = $(common-objpfx)linuxthreads/libpthread.a
bounded-thread-library = $(common-objpfx)linuxthreads/libpthread_b.a bounded-thread-library = $(common-objpfx)linuxthreads/libpthread_b.a

View File

@ -46,12 +46,14 @@ libpthread-routines := attr cancel condvar join manager mutex ptfork \
ptw-lseek64 ptw-llseek ptw-msync ptw-nanosleep \ ptw-lseek64 ptw-llseek ptw-msync ptw-nanosleep \
ptw-open ptw-open64 ptw-pause ptw-pread ptw-pread64 \ ptw-open ptw-open64 ptw-pause ptw-pread ptw-pread64 \
ptw-pwrite ptw-pwrite64 ptw-tcdrain ptw-wait \ 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. # Don't generate deps for calls with no sources. See sysdeps/unix/Makefile.
omit-deps = $(unix-syscalls:%=ptw-%) omit-deps = $(unix-syscalls:%=ptw-%)
libpthread-shared-only-routines = pt-allocrtsig libpthread-shared-only-routines = pt-allocrtsig
libpthread-nonshared = pthread_atfork
nodelete-yes = -Wl,--enable-new-dtags,-z,nodelete nodelete-yes = -Wl,--enable-new-dtags,-z,nodelete
initfirst-yes = -Wl,--enable-new-dtags,-z,initfirst initfirst-yes = -Wl,--enable-new-dtags,-z,initfirst
LDFLAGS-pthread.so = $(nodelete-$(have-z-nodelete)) \ LDFLAGS-pthread.so = $(nodelete-$(have-z-nodelete)) \
@ -65,6 +67,14 @@ CFLAGS-tst-cancel.c = -fno-inline -fno-inline-functions
include ../Makeconfig include ../Makeconfig
ifeq ($(build-shared),yes) 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 extra-objs += crti.o crtn.o
omit-deps += crti crtn omit-deps += crti crtn
@ -92,6 +102,31 @@ endif
include ../Rules 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/ extra-B-pthread.so = -B$(common-objpfx)linuxthreads/
$(objpfx)libpthread.so: $(objpfx)crti.o $(objpfx)crtn.o $(objpfx)libpthread.so: $(objpfx)crti.o $(objpfx)crtn.o
$(objpfx)libpthread.so: +preinit += $(objpfx)crti.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) ifeq ($(build-shared),yes)
$(addprefix $(objpfx), \ $(addprefix $(objpfx), \
$(filter-out $(tests-static) $(tests-reverse) unload, \ $(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, # $(objpfx)../libc.so is used instead of $(common-objpfx)libc.so,
# since otherwise libpthread.so comes before libc.so when linking. # since otherwise libpthread.so comes before libc.so when linking.
$(addprefix $(objpfx), $(tests-reverse)): \ $(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 $(addprefix $(objpfx),$(librt-tests)): $(common-objpfx)rt/librt.so
$(objpfx)unload: $(common-objpfx)dlfcn/libdl.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 else
$(addprefix $(objpfx),$(tests) $(test-srcs)): $(objpfx)libpthread.a $(addprefix $(objpfx),$(tests) $(test-srcs)): $(objpfx)libpthread.a
$(addprefix $(objpfx),$(librt-tests)): $(common-objpfx)rt/librt.a $(addprefix $(objpfx),$(librt-tests)): $(common-objpfx)rt/librt.a

View File

@ -463,6 +463,11 @@ extern int __libc_enable_asynccancel (void) attribute_hidden;
extern void __libc_disable_asynccancel (int oldtype) extern void __libc_disable_asynccancel (int oldtype)
internal_function attribute_hidden; 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 #if !defined NOT_IN_libc
# define LIBC_CANCEL_ASYNC() \ # define LIBC_CANCEL_ASYNC() \
__libc_enable_asynccancel () __libc_enable_asynccancel ()
@ -482,6 +487,7 @@ extern void __libc_disable_asynccancel (int oldtype)
the thread functions. */ the thread functions. */
struct pthread_functions struct pthread_functions
{ {
pid_t (*ptr_pthread_fork) (struct fork_block *);
int (*ptr_pthread_attr_destroy) (pthread_attr_t *); int (*ptr_pthread_attr_destroy) (pthread_attr_t *);
int (*ptr___pthread_attr_init_2_0) (pthread_attr_t *); int (*ptr___pthread_attr_init_2_0) (pthread_attr_t *);
int (*ptr___pthread_attr_init_2_1) (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_setcancelstate) (int, int *);
int (*ptr_pthread_setcanceltype) (int, int *); int (*ptr_pthread_setcanceltype) (int, int *);
void (*ptr_pthread_do_exit) (void *retval, char *currentframe); 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); pthread_descr (*ptr_pthread_thread_self) (void);
int (*ptr_pthread_internal_tsd_set) (int key, const void * pointer); int (*ptr_pthread_internal_tsd_set) (int key, const void * pointer);
void * (*ptr_pthread_internal_tsd_get) (int key); void * (*ptr_pthread_internal_tsd_get) (int key);

View File

@ -0,0 +1,27 @@
/* Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <shlib-compat.h>
#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

View File

@ -21,96 +21,71 @@
#include "pthread.h" #include "pthread.h"
#include "internals.h" #include "internals.h"
#include <bits/libc-lock.h> #include <bits/libc-lock.h>
#include "fork.h"
struct handler_list {
void (*handler)(void);
struct handler_list * next;
};
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); extern int __libc_fork (void);
pid_t __fork(void) pid_t __pthread_fork (struct fork_block *b)
{ {
pid_t pid; 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(); __pthread_once_fork_prepare();
__flockfilelist(); __flockfilelist();
pid = __libc_fork(); pid = ARCH_FORK ();
if (pid == 0) { if (pid == 0) {
__pthread_reset_main_thread(); __pthread_reset_main_thread();
__fresetlockfiles(); __fresetlockfiles();
__pthread_once_fork_child(); __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 { } else {
__funlockfilelist(); __funlockfilelist();
__pthread_once_fork_parent(); __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; return pid;
} }
pid_t __fork (void)
{
return __libc_fork ();
}
weak_alias (__fork, fork); weak_alias (__fork, fork);
pid_t __vfork(void) pid_t __vfork(void)
{ {
return __fork(); return __libc_fork ();
} }
weak_alias (__vfork, vfork); weak_alias (__vfork, vfork);

View File

@ -238,6 +238,7 @@ static struct pthread_functions pthread_functions =
.ptr_pthread_internal_tsd_get = __pthread_internal_tsd_get, .ptr_pthread_internal_tsd_get = __pthread_internal_tsd_get,
.ptr_pthread_internal_tsd_address = __pthread_internal_tsd_address, .ptr_pthread_internal_tsd_address = __pthread_internal_tsd_address,
#endif #endif
.ptr_pthread_fork = __pthread_fork,
.ptr_pthread_attr_destroy = __pthread_attr_destroy, .ptr_pthread_attr_destroy = __pthread_attr_destroy,
#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1) #if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
.ptr___pthread_attr_init_2_0 = __pthread_attr_init_2_0, .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_setcancelstate = __pthread_setcancelstate,
.ptr_pthread_setcanceltype = __pthread_setcanceltype, .ptr_pthread_setcanceltype = __pthread_setcanceltype,
.ptr_pthread_do_exit = __pthread_do_exit, .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 # define ptr_pthread_functions &pthread_functions
#else #else

View File

@ -0,0 +1,46 @@
/* Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <fork.h>
/* 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

View File

@ -27,24 +27,23 @@ extern void __libc_longjmp (sigjmp_buf env, int val)
__attribute__ ((noreturn)); __attribute__ ((noreturn));
static void pthread_cleanup_upto(__jmp_buf target) void __pthread_cleanup_upto (__jmp_buf target, char *targetframe)
{ {
pthread_descr self = thread_self(); pthread_descr self = thread_self();
struct _pthread_cleanup_buffer * c; struct _pthread_cleanup_buffer * c;
char *currentframe = CURRENT_STACK_FRAME;
for (c = THREAD_GETMEM(self, p_cleanup); for (c = THREAD_GETMEM(self, p_cleanup);
c != NULL && _JMPBUF_UNWINDS(target, c); c != NULL && _JMPBUF_UNWINDS(target, c);
c = c->__prev) c = c->__prev)
{ {
#if _STACK_GROWS_DOWN #if _STACK_GROWS_DOWN
if ((char *) c <= currentframe) if ((char *) c <= targetframe)
{ {
c = NULL; c = NULL;
break; break;
} }
#elif _STACK_GROWS_UP #elif _STACK_GROWS_UP
if ((char *) c >= currentframe) if ((char *) c >= targetframe)
{ {
c = NULL; c = NULL;
break; break;
@ -62,12 +61,10 @@ static void pthread_cleanup_upto(__jmp_buf target)
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);
} }

View File

@ -0,0 +1,116 @@
/* Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <assert.h>
/* 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 */

View File

@ -0,0 +1,3 @@
ifeq ($(subdir),linuxthreads)
sysdep_routines += register-atfork unregister-atfork
endif

View File

@ -0,0 +1,5 @@
libc {
GLIBC_2.3.2 {
__register_atfork;
}
}

View File

@ -0,0 +1,40 @@
/* Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h>
#include "fork.h"
#include <bits/libc-lock.h>
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)

View File

@ -0,0 +1,59 @@
/* Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <list.h>
#include <bits/libc-lock.h>
#include <sysdep.h>
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

View File

@ -0,0 +1,25 @@
/* Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <signal.h>
#include <sysdep.h>
#define ARCH_FORK() INLINE_SYSCALL (clone, 2, SIGCHLD, 0)
#include_next <fork.h>

View File

@ -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 <setjmp.h>
#include <stddef.h>
#include <bits/libc-lock.h>
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);
}

View File

@ -0,0 +1,87 @@
/* Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h>
#include <stdlib.h>
#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;
}

View File

@ -0,0 +1,34 @@
/* Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <sysdep.h>
#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 <fork.h>

View File

@ -0,0 +1,49 @@
/* Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h>
#include <stdlib.h>
#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);
}

View File

@ -72,8 +72,14 @@ __libc_lock_define (typedef, mutex_t)
#endif #endif
/* This is defined by newer gcc version unique for each module. */
extern void *__dso_handle __attribute__ ((__weak__));
#include <fork.h>
#define thread_atfork(prepare, parent, child) \ #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) #elif defined(MUTEX_INITIALIZER)
/* Assume hurd, with cthreads */ /* Assume hurd, with cthreads */

View File

@ -1,5 +1,8 @@
2002-12-30 Ulrich Drepper <drepper@redhat.com> 2002-12-30 Ulrich Drepper <drepper@redhat.com>
* sysdeps/pthread/pt-initfini.c (call_initialize_minimal): Mark
__pthread_initialize_minimal as hidden.
* init.c (__pthread_initialize_minimal_internal): Don't mark as * init.c (__pthread_initialize_minimal_internal): Don't mark as
constructor. constructor.

View File

@ -1,5 +1,5 @@
/* Special .init and .fini section support. Linuxthread version. /* 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. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it The GNU C Library is free software; you can redistribute it
@ -65,7 +65,8 @@ asm ("\n/*@_init_PROLOG_BEGINS*/");
static void static void
call_initialize_minimal (void) call_initialize_minimal (void)
{ {
extern void __pthread_initialize_minimal (void); extern void __pthread_initialize_minimal (void)
__attribute ((visibility ("hidden")));
__pthread_initialize_minimal (); __pthread_initialize_minimal ();
} }