2003-04-11  Ulrich Drepper  <drepper@redhat.com>

	* sysdeps/generic/libc-start.c: Cleanup MAIN_AUXVEC_ARG handling.
	Remove HAVE_CANCELBUF code.  Replace with code using the new
	initializers for unwind-based cleanup handling.
	* sysdeps/generic/unwind.h: Update from latest gcc version.
	* sysdeps/unix/sysv/linux/i386/sysdep.h: Define labels in a few
	places to allow unwind data generation.
	* sysdeps/i386/bits/setjmp.h: Allow file to be included multiple times.
	* sysdeps/x86_64/bits/setjmp.h: Likewise.
	* sysdeps/sh/bits/setjmp.h: Likewise.
	* sysdeps/powerpc/bits/setjmp.h: Likewise.
	* sysdeps/unix/sysv/linux/ia64/bits/setjmp.h: Likewise.
	* sysdeps/alpha/bits/setjmp.h: Likewise.
This commit is contained in:
Ulrich Drepper 2003-04-12 00:58:26 +00:00
parent 877e51b20f
commit 09d65ff393
22 changed files with 730 additions and 103 deletions

View File

@ -1,3 +1,18 @@
2003-04-11 Ulrich Drepper <drepper@redhat.com>
* sysdeps/generic/libc-start.c: Cleanup MAIN_AUXVEC_ARG handling.
Remove HAVE_CANCELBUF code. Replace with code using the new
initializers for unwind-based cleanup handling.
* sysdeps/generic/unwind.h: Update from latest gcc version.
* sysdeps/unix/sysv/linux/i386/sysdep.h: Define labels in a few
places to allow unwind data generation.
* sysdeps/i386/bits/setjmp.h: Allow file to be included multiple times.
* sysdeps/x86_64/bits/setjmp.h: Likewise.
* sysdeps/sh/bits/setjmp.h: Likewise.
* sysdeps/powerpc/bits/setjmp.h: Likewise.
* sysdeps/unix/sysv/linux/ia64/bits/setjmp.h: Likewise.
* sysdeps/alpha/bits/setjmp.h: Likewise.
2003-04-11 Roland McGrath <roland@redhat.com>
* csu/tst-empty.c: New file.

View File

@ -1,3 +1,45 @@
2003-04-11 Ulrich Drepper <drepper@redhat.com>
* pthread.h: Define new data structure for cleanup buffer. Declare
new cleanup handler interfaces.
* descr.h: Include <unwind.h> if necessary. Define pthread_unwind_buf.
(struct pthread): Add cleanup_jmp_buf pointer. Define
HAVE_CLEANUP_JMP_BUF and not HAVE_CANCELBUF.
* pthreadP.h: Declare __pthread_unwind. Define __do_cancel to use
it. Declare old cleanup handler installation functions.
* cleanup.c: Rewrite. Install handler for unwind-based cleanup
handling.
* cleanup_defer.c: Likewise.
* cleanup_compat.c: New file. Old cleanup code.
* cleanup_def_compat.c: New file. Old cleanup code.
* pthread_create.c (start_thread): Initialize cleanup_jmp_buf element
if own thread descriptor.
* unwind.c: New file.
* forward.c: Add __pthread_unwind.
* init.c (pthread_functions): Add __pthread_unwind.
* sysdeps/pthread/pthread-functions.s (struct pthread_functions):
Add ptr___pthread_unwind.
* Versions [GLIBC_2.3.3] (libpthread): Export new cleanup handling
and unwind function.
* Makefile (libpthread-routines): Add cleanup_compat,
cleanup_def_compat, and unwind. Define CFLAGS to enable unwind
table generation if necessary.
* version.c: Record whether unwind support is compiled in.
* sysdeps/pthread/configure.in: Add checks for unwind unterfaces.
* sysdeps/pthread/bits/libc-lock.h: Add prototypes of the old cleanup
handler interfaces.
* sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Add quite a bit of
complication to generate unwind information for syscall wrappers.
* sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Define
__cleanup_fct_attribute.
* Makefile: Add rules to build and run tst-cleanup0.
* tst-cleanup0.c: New file.
* tst-cleanup0.expect: New file.
* pthread_create.c (deallocate_tsd): Don't take parameter. Adjust
caller. Optimize to avoid often unecessary local variable.
2003-04-11 Roland McGrath <roland@redhat.com>
* Makefile ($(objpfx)multidir.mk): New target, generated makefile that

View File

@ -98,7 +98,8 @@ libpthread-routines = init events version \
sem_open sem_close sem_unlink \
sem_getvalue \
sem_wait sem_trywait sem_timedwait sem_post \
cleanup cleanup_defer \
cleanup cleanup_defer cleanup_compat \
cleanup_defer_compat unwind \
pt-longjmp \
cancellation \
lowlevellock lowlevelmutex \
@ -122,6 +123,10 @@ libpthread-static-only-routines = pthread_atfork
libpthread-nonshared = pthread_atfork
CFLAGS-pthread_atfork.c = -DNOT_IN_libc
CFLAGS-init.c = -fexceptions -fasynchronous-unwind-tables
CFLAGS-unwind.c = -fexceptions
CFLAGS-cancellation.c = -fasynchronous-unwind-tables
CFLAGS-libc-cancellation.c = -fasynchronous-unwind-tables
# Don't generate deps for calls with no sources. See sysdeps/unix/Makefile.
omit-deps = $(unix-syscalls:%=ptw-%)
@ -153,7 +158,7 @@ tests = tst-attr1 tst-attr2 \
tst-cancel1 tst-cancel2 tst-cancel3 tst-cancel4 tst-cancel5 \
tst-cancel6 tst-cancel7 tst-cancel8 tst-cancel9 tst-cancel10 \
tst-cancel11 \
tst-cleanup1 tst-cleanup2 tst-cleanup3 \
tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 \
tst-flock1 tst-flock2 \
tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \
tst-exec1 tst-exec2 tst-exec3 \
@ -208,6 +213,9 @@ CFLAGS-flockfile.c = -D_IO_MTSAFE_IO
CFLAGS-ftrylockfile.c = -D_IO_MTSAFE_IO
CFLAGS-funlockfile.c = -D_IO_MTSAFE_IO
# Ugly, ugly. We have to link with libgcc_eh but how?
link-libc-static := $(common-objpfx)libc.a $(gnulib) -lgcc_eh $(common-objpfx)libc.a
ifeq ($(build-static),yes)
tests-static += tst-locale1 tst-locale2
endif
@ -220,7 +228,6 @@ ifeq (yes,$(build-shared))
# Make sure these things are built in the `make lib' pass so they can be used
# to run programs during the `make others' pass.
lib-noranlib: $(addprefix $(objpfx),$(extra-objs))
endif
# 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.
@ -229,6 +236,7 @@ endif
# 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),\
@ -245,6 +253,8 @@ $(inst_libdir)/libpthread.so: $(common-objpfx)format.lds \
mv -f $@.new $@
$(inst_libdir)/libpthread_nonshared.a: $(objpfx)libpthread_nonshared.a
$(do-install)
endif
# 'pthread_self' is a simple memory or register load. Setting up the
# stack frame is more work than the actual operation. Disable the
@ -313,6 +323,9 @@ $(objpfx)pt-initfini.s: pt-initfini.c
$(compile.c) -S $(CFLAGS-pt-initfini.s) -finhibit-size-directive \
$(patsubst -f%,-fno-%,$(exceptions)) -o $@
$(objpfx)tst-cleanup0.out: /dev/null $(objpfx)tst-cleanup0
$(make-test-out) 2>&1 | cmp - tst-cleanup0.expect >& $@
# We only have one kind of startup code files. Static binaries and
# shared libraries are build using the PIC version.
$(objpfx)crti.S: $(objpfx)pt-initfini.s

View File

@ -211,6 +211,11 @@ libpthread {
# Proposed API extensions.
pthread_tryjoin_np; pthread_timedjoin_np;
# New cancellation cleanup handling.
__pthread_register_cancel; __pthread_unregister_cancel;
__pthread_register_cancel_defer; __pthread_unregister_cancel_restore;
__pthread_unwind_next;
}
GLIBC_PRIVATE {

View File

@ -345,6 +345,19 @@ typedef pthread_key_t __libc_key_t;
} while (0)
/* Note that for I/O cleanup handling we are using the old-style
cancel handling. It does not have to be integrated with C++ snce
no C++ code is called in the middle. The old-style handling is
faster and the support is not going away. */
extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer,
void (*routine) (void *), void *arg);
extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer,
int execute);
extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer,
void (*routine) (void *), void *arg);
extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer,
int execute);
/* Start critical region with cleanup. */
#define __libc_cleanup_region_start(DOIT, FCT, ARG) \
{ struct _pthread_cleanup_buffer _buffer; \

View File

@ -5,3 +5,58 @@ if test "x$libc_cv_gcc___thread" != xyes; then
echo "$as_me: error: compiler support for __thread is required" >&2;}
{ (exit 1); exit 1; }; }
fi
echo "$as_me:$LINENO: checking for forced unwind support" >&5
echo $ECHO_N "checking for forced unwind support... $ECHO_C" >&6
if test "${libc_cv_forced_unwind+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
cat >conftest.$ac_ext <<_ACEOF
#line $LINENO "configure"
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#include <unwind.h>
int
main ()
{
struct _Unwind_Exception exc;
struct _Unwind_Context *context;
_Unwind_GetCFA (context)
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext conftest$ac_exeext
if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
(eval $ac_link) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } &&
{ ac_try='test -s conftest$ac_exeext'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
libc_cv_forced_unwind=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
libc_cv_forced_unwind=no
fi
rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
fi
echo "$as_me:$LINENO: result: $libc_cv_forced_unwind" >&5
echo "${ECHO_T}$libc_cv_forced_unwind" >&6
if test $libc_cv_forced_unwind = yes; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_FORCED_UNWIND 1
_ACEOF
fi

View File

@ -4,3 +4,16 @@ GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
if test "x$libc_cv_gcc___thread" != xyes; then
AC_MSG_ERROR(compiler support for __thread is required)
fi
dnl Iff <unwind.h> is available, make sure it is the right one and it
dnl contains struct _Unwind_Exception.
AC_CACHE_CHECK(dnl
for forced unwind support, libc_cv_forced_unwind, [dnl
AC_TRY_LINK([#include <unwind.h>], [
struct _Unwind_Exception exc;
struct _Unwind_Context *context;
_Unwind_GetCFA (context)],
libc_cv_forced_unwind=yes, libc_cv_forced_unwind=no)])
if test $libc_cv_forced_unwind = yes; then
AC_DEFINE(HAVE_FORCED_UNWIND)
fi

View File

@ -85,6 +85,8 @@ struct pthread_functions
int);
#define HAVE_PTR_NTHREADS
int *ptr_nthreads;
void (*ptr___pthread_unwind) (__pthread_unwind_buf_t *)
__attribute ((noreturn)) __cleanup_fct_attribute;
};
/* Variable in libc.so. */

View File

@ -26,6 +26,7 @@
#define __need_sigset_t
#include <signal.h>
#include <bits/pthreadtypes.h>
#include <bits/setjmp.h>
/* Detach state. */
@ -380,6 +381,24 @@ extern int pthread_cancel (pthread_t __th) __THROW;
extern void pthread_testcancel (void) __THROW;
/* Cancellation handling with integration into exception handling. */
typedef struct
{
void *__pad[16];
struct
{
__jmp_buf __cancel_jmp_buf;
int __mask_was_saved;
} __cancel_jmp_buf[1];
} __pthread_unwind_buf_t __attribute__ ((__aligned__));
/* No special attributes by default. */
#ifndef __cleanup_fct_attribute
# define __cleanup_fct_attribute
#endif
/* Install a cleanup handler: ROUTINE will be called with arguments ARG
when the thread is cancelled or calls pthread_exit. ROUTINE will also
be called with arguments ARG when the matching pthread_cleanup_pop
@ -387,44 +406,84 @@ extern void pthread_testcancel (void) __THROW;
pthread_cleanup_push and pthread_cleanup_pop are macros and must always
be used in matching pairs at the same nesting level of braces. */
#define pthread_cleanup_push(routine,arg) \
{ struct _pthread_cleanup_buffer _buffer; \
_pthread_cleanup_push (&_buffer, (routine), (arg));
extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
void (*__routine) (void *), void *__arg)
__THROW;
#define pthread_cleanup_push(routine, arg) \
do { \
__pthread_unwind_buf_t __cancel_buf; \
void (*__cancel_routine) (void *) = (routine); \
void *__cancel_arg = (arg); \
int not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) \
__cancel_buf.__cancel_jmp_buf, 0); \
if (__builtin_expect (not_first_call, 0)) \
{ \
__cancel_routine (__cancel_arg); \
__pthread_unwind_next (&__cancel_buf); \
/* NOTREACHED */ \
} \
\
__pthread_register_cancel (&__cancel_buf); \
do {
extern void __pthread_register_cancel (__pthread_unwind_buf_t *__buf)
__cleanup_fct_attribute;
/* Remove a cleanup handler installed by the matching pthread_cleanup_push.
If EXECUTE is non-zero, the handler function is called. */
#define pthread_cleanup_pop(execute) \
_pthread_cleanup_pop (&_buffer, (execute)); }
extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
int __execute) __THROW;
} while (0); \
__pthread_unregister_cancel (&__cancel_buf); \
if (execute) \
__cancel_routine (__cancel_arg); \
} while (0)
extern void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf)
__cleanup_fct_attribute;
#ifdef __USE_GNU
/* Install a cleanup handler as pthread_cleanup_push does, but also
saves the current cancellation type and sets it to deferred
cancellation. */
# define pthread_cleanup_push_defer_np(routine,arg) \
{ struct _pthread_cleanup_buffer _buffer; \
_pthread_cleanup_push_defer (&_buffer, (routine), (arg));
extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
void (*__routine) (void *),
void *__arg) __THROW;
# define pthread_cleanup_push_defer(routine, arg) \
do { \
__pthread_unwind_buf_t __cancel_buf; \
void (*__cancel_routine) (void *) = (routine); \
void *__cancel_arg = (arg); \
int not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) \
__cancel_buf.__cancel_jmp_buf, 0); \
if (__builtin_expect (not_first_call, 0)) \
{ \
__cancel_routine (__cancel_arg); \
__pthread_unwind_next (&__cancel_buf); \
/* NOTREACHED */ \
} \
\
__pthread_register_cancel_defer (&__cancel_buf); \
do {
extern void __pthread_register_cancel_defer (__pthread_unwind_buf_t *__buf)
__cleanup_fct_attribute;
/* Remove a cleanup handler as pthread_cleanup_pop does, but also
restores the cancellation type that was in effect when the matching
pthread_cleanup_push_defer was called. */
# define pthread_cleanup_pop_restore_np(execute) \
_pthread_cleanup_pop_restore (&_buffer, (execute)); }
extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
int __execute) __THROW;
# define pthread_cleanup_pop_cleanup(execute) \
} while (0); \
__pthread_unregister_cancel_restore (&__cancel_buf); \
if (execute) \
__cancel_routine (__cancel_arg); \
} while (0)
extern void __pthread_unregister_cancel_restore (__pthread_unwind_buf_t *__buf)
__cleanup_fct_attribute;
#endif
/* Internal interface to initiate cleanup. */
extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf)
__cleanup_fct_attribute __attribute ((__noreturn__))
#ifndef SHARED
__attribute ((__weak__))
#endif
;
/* Function used in the macros. */
struct __jmp_buf_tag;
extern int __sigsetjmp (struct __jmp_buf_tag __env[1], int __savemask) __THROW;
/* Mutex handling. */

View File

@ -149,4 +149,7 @@ typedef union
#endif
/* Extra attributes for the cleanup functions. */
#define __cleanup_fct_attribute __attribute ((regparm (1)))
#endif /* bits/pthreadtypes.h */

View File

@ -29,6 +29,7 @@
# define PSEUDO(name, syscall_name, args) \
.text; \
ENTRY (name) \
L(name##START): \
cmpl $0, %gs:MULTIPLE_THREADS_OFFSET; \
jne L(pseudo_cancel); \
DO_CALL (syscall_name, args); \
@ -38,29 +39,262 @@
L(pseudo_cancel): \
CENABLE \
SAVE_OLDTYPE_##args \
PUSHARGS_##args \
PUSHCARGS_##args \
DOCARGS_##args \
movl $SYS_ify (syscall_name), %eax; \
ENTER_KERNEL \
POPARGS_##args; \
POPCARGS_##args \
/* Until we can handle unwinding from the sysenter page the kernel \
provides we cannot use ENTER_KERNEL here. */ \
int $0x80; \
POPCARGS_##args; \
POPSTATE_##args \
cmpl $-4095, %eax; \
jae SYSCALL_ERROR_LABEL; \
L(pseudo_end):
L(pseudo_end): \
\
/* Create unwinding information for the syscall wrapper. */ \
.section .eh_frame,"a",@progbits; \
L(STARTFRAME): \
/* Length of the CIE. */ \
.long L(ENDCIE)-L(STARTCIE); \
L(STARTCIE): \
/* CIE ID. */ \
.long 0; \
/* Version number. */ \
.byte 1; \
/* NUL-terminated augmentation string. Note "z" means there is an \
augmentation value later on. */ \
.string "zR"; \
/* Code alignment factor. */ \
.uleb128 1; \
/* Data alignment factor. */ \
.sleb128 -4; \
/* Return address register column. */ \
.byte 8; \
/* Augmentation value length. */ \
.uleb128 1; \
/* Encoding: DW_EH_PE_pcrel + DW_EH_PE_sdata4. */ \
.byte 0x1b; \
/* Start of the table initialization. */ \
.byte 0xc; \
.uleb128 4; \
.uleb128 4; \
.byte 0x88; \
.uleb128 1; \
.align 4; \
L(ENDCIE): \
/* Length of the FDE. */ \
.long L(ENDFDE)-L(STARTFDE); \
L(STARTFDE): \
/* CIE pointer. */ \
.long L(STARTFDE)-L(STARTFRAME); \
/* PC-relative start address of the code. */ \
.long L(name##START)-.; \
/* Length of the code. */ \
.long L(name##END)-L(name##START); \
/* No augmentation data. */ \
.uleb128 0; \
/* The rest of the code depends on the number of parameters the syscall \
takes. */ \
EH_FRAME_##args(name); \
.align 4; \
L(ENDFDE): \
.previous
/* Callframe description for syscalls without parameters. This is very
simple. The only place the stack pointer is changed is when the old
cancellation state value is saved. */
# define EH_FRAME_0(name) \
.byte 4; \
.long L(PUSHSTATE)-name; \
.byte 14; \
.uleb128 8; \
.byte 4; \
.long L(POPSTATE)-L(PUSHSTATE); \
.byte 14; \
.uleb128 4
/* For syscalls with one and two parameters the code is the same as for
those which take no parameter. */
# define EH_FRAME_1(name) EH_FRAME_0 (name)
# define EH_FRAME_2(name) EH_FRAME_1 (name)
/* For syscalls with three parameters the stack pointer is changed
also to save the content of the %ebx register. */
# define EH_FRAME_3(name) \
.byte 4; \
.long L(PUSHBX1)-name; \
.byte 14; \
.uleb128 8; \
.byte 4; \
.long L(POPBX1)-L(PUSHBX1); \
.byte 14; \
.uleb128 4; \
.byte 4; \
.long L(PUSHSTATE)-L(POPBX1); \
.byte 14; \
.uleb128 8; \
.byte 4; \
.long L(PUSHBX2)-L(PUSHSTATE); \
.byte 14; \
.uleb128 12; \
.byte 4; \
.long L(POPBX2)-L(PUSHBX2); \
.byte 14; \
.uleb128 8; \
.byte 4; \
.long L(POPSTATE)-L(POPBX2); \
.byte 14; \
.uleb128 4
/* With four parameters the syscall wrappers have to save %ebx and %esi. */
# define EH_FRAME_4(name) \
.byte 4; \
.long L(PUSHSI1)-name; \
.byte 14; \
.uleb128 8; \
.byte 4; \
.long L(PUSHBX1)-L(PUSHSI1); \
.byte 14; \
.uleb128 12; \
.byte 4; \
.long L(POPBX1)-L(PUSHBX1); \
.byte 14; \
.uleb128 8; \
.byte 4; \
.long L(POPSI1)-L(POPBX1); \
.byte 14; \
.uleb128 4; \
.byte 4; \
.long L(PUSHSTATE)-L(POPSI1); \
.byte 14; \
.uleb128 8; \
.byte 4; \
.long L(PUSHSI2)-L(PUSHSTATE); \
.byte 14; \
.uleb128 12; \
.byte 4; \
.long L(PUSHBX2)-L(PUSHSI2); \
.byte 14; \
.uleb128 16; \
.byte 4; \
.long L(POPBX2)-L(PUSHBX2); \
.byte 14; \
.uleb128 12; \
.byte 4; \
.long L(POPSI2)-L(POPBX2); \
.byte 14; \
.uleb128 8; \
.byte 4; \
.long L(POPSTATE)-L(POPSI2); \
.byte 14; \
.uleb128 4
/* With five parameters the syscall wrappers have to save %ebx, %esi,
and %edi. */
# define EH_FRAME_5(name) \
.byte 4; \
.long L(PUSHDI1)-name; \
.byte 14; \
.uleb128 8; \
.byte 4; \
.long L(PUSHSI1)-L(PUSHDI1); \
.byte 14; \
.uleb128 12; \
.byte 4; \
.long L(PUSHBX1)-L(PUSHSI1); \
.byte 14; \
.uleb128 16; \
.byte 4; \
.long L(POPBX1)-L(PUSHBX1); \
.byte 14; \
.uleb128 12; \
.byte 4; \
.long L(POPSI1)-L(POPBX1); \
.byte 14; \
.uleb128 8; \
.byte 4; \
.long L(POPDI1)-L(POPSI1); \
.byte 14; \
.uleb128 4; \
.byte 4; \
.long L(PUSHSTATE)-L(POPDI1); \
.byte 14; \
.uleb128 8; \
.byte 4; \
.long L(PUSHDI2)-L(PUSHSTATE); \
.byte 14; \
.uleb128 12; \
.byte 4; \
.long L(PUSHSI2)-L(PUSHDI2); \
.byte 14; \
.uleb128 16; \
.byte 4; \
.long L(PUSHBX2)-L(PUSHSI2); \
.byte 14; \
.uleb128 20; \
.byte 4; \
.long L(POPBX2)-L(PUSHBX2); \
.byte 14; \
.uleb128 16; \
.byte 4; \
.long L(POPSI2)-L(POPBX2); \
.byte 14; \
.uleb128 12; \
.byte 4; \
.long L(POPDI2)-L(POPSI2); \
.byte 14; \
.uleb128 8; \
.byte 4; \
.long L(POPSTATE)-L(POPDI2); \
.byte 14; \
.uleb128 4
# undef ASM_SIZE_DIRECTIVE
# define ASM_SIZE_DIRECTIVE(name) L(name##END): .size name,.-name;
# define SAVE_OLDTYPE_0 movl %eax, %edx;
# define SAVE_OLDTYPE_1 SAVE_OLDTYPE_0
# define SAVE_OLDTYPE_2 pushl %eax;
# define SAVE_OLDTYPE_2 pushl %eax; L(PUSHSTATE):
# define SAVE_OLDTYPE_3 SAVE_OLDTYPE_2
# define SAVE_OLDTYPE_4 SAVE_OLDTYPE_2
# define SAVE_OLDTYPE_5 SAVE_OLDTYPE_2
# define DOCARGS_0 DOARGS_0
# define DOCARGS_1 DOARGS_1
# define PUSHCARGS_0 /* No arguments to push. */
# define DOCARGS_0 /* No arguments to frob. */
# define POPCARGS_0 /* No arguments to pop. */
# define _PUSHCARGS_0 /* No arguments to push. */
# define _POPCARGS_0 /* No arguments to pop. */
# define PUSHCARGS_1 movl %ebx, %edx; PUSHCARGS_0
# define DOCARGS_1 _DOARGS_1 (4)
# define POPCARGS_1 POPCARGS_0; movl %edx, %ebx
# define _PUSHCARGS_1 pushl %ebx; L(PUSHBX2): _PUSHCARGS_0
# define _POPCARGS_1 _POPCARGS_0; popl %ebx; L(POPBX2):
# define PUSHCARGS_2 PUSHCARGS_1
# define DOCARGS_2 _DOARGS_2 (12)
# define POPCARGS_2 POPCARGS_1
# define _PUSHCARGS_2 _PUSHCARGS_1
# define _POPCARGS_2 _POPCARGS_1
# define PUSHCARGS_3 _PUSHCARGS_2
# define DOCARGS_3 _DOARGS_3 (20)
# define POPCARGS_3 _POPCARGS_3
# define _PUSHCARGS_3 _PUSHCARGS_2
# define _POPCARGS_3 _POPCARGS_2
# define PUSHCARGS_4 _PUSHCARGS_4
# define DOCARGS_4 _DOARGS_4 (28)
# define POPCARGS_4 _POPCARGS_4
# define _PUSHCARGS_4 pushl %esi; L(PUSHSI2): _PUSHCARGS_3
# define _POPCARGS_4 _POPCARGS_3; popl %esi; L(POPSI2):
# define PUSHCARGS_5 _PUSHCARGS_5
# define DOCARGS_5 _DOARGS_5 (36)
# define POPCARGS_5 _POPCARGS_5
# define _PUSHCARGS_5 pushl %edi; L(PUSHDI2): _PUSHCARGS_4
# define _POPCARGS_5 _POPCARGS_4; popl %edi; L(POPDI2):
# ifdef IS_IN_libpthread
# define CENABLE call __pthread_enable_asynccancel;
@ -69,12 +303,13 @@
# define CENABLE call __libc_enable_asynccancel;
# define CDISABLE call __libc_disable_asynccancel
# endif
# define POPCARGS_0 pushl %eax; movl %ecx, %eax; CDISABLE; popl %eax;
# define POPCARGS_1 POPCARGS_0
# define POPCARGS_2 xchgl (%esp), %eax; CDISABLE; popl %eax;
# define POPCARGS_3 POPCARGS_2
# define POPCARGS_4 POPCARGS_2
# define POPCARGS_5 POPCARGS_2
# define POPSTATE_0 \
pushl %eax; L(PUSHSTATE): movl %ecx, %eax; CDISABLE; popl %eax; L(POPSTATE):
# define POPSTATE_1 POPSTATE_0
# define POPSTATE_2 xchgl (%esp), %eax; CDISABLE; popl %eax; L(POPSTATE):
# define POPSTATE_3 POPSTATE_2
# define POPSTATE_4 POPSTATE_3
# define POPSTATE_5 POPSTATE_4
# ifndef __ASSEMBLER__
# define SINGLE_THREAD_P \

112
nptl/unwind.c Normal file
View File

@ -0,0 +1,112 @@
/* Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>
and Richard Henderson <rth@redhat.com>, 2003.
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 <stdlib.h>
#include "pthreadP.h"
#ifdef HAVE_FORCED_UNWIND
static _Unwind_Reason_Code
unwind_stop (int version, _Unwind_Action actions,
_Unwind_Exception_Class exc_class,
struct _Unwind_Exception *exc_obj,
struct _Unwind_Context *context, void *stop_parameter)
{
struct pthread_unwind_buf *buf = stop_parameter;
/* Do longjmp if we're at "end of stack", aka "end of unwind data".
We assume there are only C frame without unwind data in between
here and the jmp_buf target. Otherwise simply note that the CFA
of a function is NOT within it's stack frame; it's the SP of the
previous frame. */
if ((actions & _UA_END_OF_STACK)
|| ! _JMPBUF_UNWINDS (buf->cancel_jmp_buf[0].jmp_buf,
_Unwind_GetCFA (context)))
__libc_longjmp ((struct __jmp_buf_tag *) buf->cancel_jmp_buf, 1);
return _URC_NO_REASON;
}
static void
unwind_cleanup (_Unwind_Reason_Code reason, struct _Unwind_Exception *exc)
{
/* Nothing to do. */
}
#endif /* have forced unwind */
void
__cleanup_fct_attribute __attribute ((noreturn))
__pthread_unwind (__pthread_unwind_buf_t *buf)
{
struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
struct pthread *self = THREAD_SELF;
/* Handle the compatibility stuff first. Execute all handlers
registered with the old method. We don't execute them in order,
instead, they will run first. */
struct _pthread_cleanup_buffer *oldp = ibuf->priv.data.cleanup;
struct _pthread_cleanup_buffer *curp = THREAD_GETMEM (self, cleanup);
while (curp != oldp)
{
/* Pointer to the next element. */
struct _pthread_cleanup_buffer *nextp = curp->__prev;
/* Call the handler. */
curp->__routine (curp->__arg);
/* To the next. */
curp = nextp;
}
/* Mark the current element as handled. */
THREAD_SETMEM (self, cleanup, curp);
#ifdef HAVE_FORCED_UNWIND
/* This is not a catchable exception, so don't provide any details about
the exception type. We do need to initialize the field though. */
ibuf->priv.data.exc.exception_class = 0;
ibuf->priv.data.exc.exception_cleanup = unwind_cleanup;
_Unwind_ForcedUnwind (&ibuf->priv.data.exc, unwind_stop, ibuf);
#else
/* We simply jump to the registered setjmp buffer. */
__libc_longjmp ((struct __jmp_buf_tag *) ibuf->cancel_jmp_buf, 1);
#endif
/* NOTREACHED */
/* We better do not get here. */
abort ();
}
void
__cleanup_fct_attribute __attribute ((noreturn))
__pthread_unwind_next (__pthread_unwind_buf_t *buf)
{
struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
__pthread_unwind (ibuf->priv.data.prev);
}

View File

@ -26,7 +26,11 @@ static const char banner[] =
"Copyright (C) 2003 Free Software Foundation, Inc.\n\
This is free software; see the source for copying conditions.\n\
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n\
PARTICULAR PURPOSE.\n";
PARTICULAR PURPOSE.\n"
#ifdef HAVE_FORCED_UNWIND
"Forced unwind support included.\n"
#endif
;
extern void __nptl_main (void) __attribute__ ((noreturn));

View File

@ -1,5 +1,5 @@
/* Define the machine-dependent type `jmp_buf'. Alpha version.
Copyright (C) 1992, 1997 Free Software Foundation, Inc.
Copyright (C) 1992, 1997, 2003 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
@ -17,7 +17,10 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef _SETJMP_H
#ifndef _BITS_SETJMP_H
#define _BITS_SETJMP_H 1
#if !defined _SETJMP_H && !defined _PTHREAD_H
# error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
#endif
@ -80,3 +83,5 @@ typedef long int __jmp_buf[17];
#define _JMPBUF_UNWINDS(_jmpbuf, _address) \
((void *)(_address) < (void *)((_jmpbuf)[JB_SP]))
#endif
#endif /* bits/setjmp.h */

View File

@ -51,12 +51,17 @@ extern void __pthread_initialize_minimal (void)
# define LIBC_START_MAIN BP_SYM (__libc_start_main)
#endif
STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
#ifdef MAIN_AUXVEC_ARG
, void *
/* main gets passed a pointer to the auxiliary. */
# define MAIN_AUXVEC_DECL , void *
# define MAIN_AUXVEC_PARAM , auxvec
#else
# define MAIN_AUXVEC_DECL
# define MAIN_AUXVEC_PARAM
#endif
),
STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
MAIN_AUXVEC_DECL),
int argc,
char *__unbounded *__unbounded ubp_av,
#ifdef LIBC_START_MAIN_AUXVEC_ARG
@ -73,11 +78,7 @@ STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
__attribute__ ((noreturn));
STATIC int
LIBC_START_MAIN (int (*main) (int, char **, char **
#ifdef MAIN_AUXVEC_ARG
, void *
#endif
),
LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
int argc, char *__unbounded *__unbounded ubp_av,
#ifdef LIBC_START_MAIN_AUXVEC_ARG
ElfW(auxv_t) *__unbounded auxvec,
@ -172,10 +173,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char **
if (init)
(*init) (
#ifdef INIT_MAIN_ARGS
argc, argv, __environ
# ifdef MAIN_AUXVEC_ARG
, auxvec
# endif
argc, argv, __environ MAIN_AUXVEC_PARAM
#endif
);
@ -184,38 +182,45 @@ LIBC_START_MAIN (int (*main) (int, char **, char **
_dl_debug_printf ("\ntransferring control: %s\n\n", argv[0]);
#endif
#ifdef HAVE_CANCELBUF
if (setjmp (THREAD_SELF->cancelbuf) == 0)
#endif
#ifdef HAVE_CLEANUP_JMP_BUF
/* Memory for the cancellation buffer. */
struct pthread_unwind_buf unwind_buf;
int not_first_call;
not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
if (__builtin_expect (! not_first_call, 1))
{
/* XXX This is where the try/finally handling must be used. */
struct pthread *self = THREAD_SELF;
result = main (argc, argv, __environ
#ifdef MAIN_AUXVEC_ARG
, auxvec
#endif
/* Store old info. */
unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf);
unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup);
);
/* Store the new cleanup handler info. */
THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf);
/* Run the program. */
result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);
}
#ifdef HAVE_CANCELBUF
else
{
# ifdef HAVE_PTR_NTHREADS
/* One less thread. Decrement the counter. If it is zero we
terminate the entire process. */
result = 0;
# ifdef SHARED
# ifdef SHARED
int *const ptr = __libc_pthread_functions.ptr_nthreads;
# else
# else
extern int __nptl_nthreads __attribute ((weak));
int *const ptr = &__nptl_nthreads;
# endif
# endif
if (! atomic_decrement_and_test (ptr))
# endif
/* Not much left to do but to exit the thread, not the process. */
__exit_thread (0);
}
#else
/* Nothing fancy, just call the function. */
result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);
#endif
exit (result);

View File

@ -1,26 +1,36 @@
/* Exception handling and frame unwind runtime interface routines.
Copyright (C) 2001 Free Software Foundation, Inc.
Copyright (C) 2001, 2003 Free Software Foundation, Inc.
This file is part of GNU CC.
This file is part of GCC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC 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 General Public License for more details.
GCC 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 General Public
License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
/* As a special exception, if you include this header file into source
files compiled by GCC, this header file does not by itself cause
the resulting executable to be covered by the GNU General Public
License. This exception does not however invalidate any other
reasons why the executable file might be covered by the GNU General
Public License. */
/* This is derived from the C++ ABI for IA-64. Where we diverge
for cross-architecture compatibility are noted with "@@@". */
#ifndef _UNWIND_H
#define _UNWIND_H 1
#ifdef __cplusplus
extern "C" {
#endif
@ -31,7 +41,12 @@ extern "C" {
inefficient for 32-bit and smaller machines. */
typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));
typedef signed _Unwind_Sword __attribute__((__mode__(__word__)));
#if defined(__ia64__) && defined(__hpux__)
typedef unsigned _Unwind_Ptr __attribute__((__mode__(__word__)));
#else
typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
#endif
typedef unsigned _Unwind_Internal_Ptr __attribute__((__mode__(__pointer__)));
/* @@@ The IA-64 ABI uses a 64-bit word to identify the producer and
consumer of an exception. We'll go along with this for now even on
@ -87,6 +102,7 @@ typedef int _Unwind_Action;
#define _UA_CLEANUP_PHASE 2
#define _UA_HANDLER_FRAME 4
#define _UA_FORCE_UNWIND 8
#define _UA_END_OF_STACK 16
/* This is an opaque type used to refer to a system-specific data
structure used by the system unwinder. This context is created and
@ -125,6 +141,9 @@ extern void _Unwind_SetGR (struct _Unwind_Context *, int, _Unwind_Word);
extern _Unwind_Ptr _Unwind_GetIP (struct _Unwind_Context *);
extern void _Unwind_SetIP (struct _Unwind_Context *, _Unwind_Ptr);
/* @@@ Retrieve the CFA of the given context. */
extern _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *);
extern void *_Unwind_GetLanguageSpecificData (struct _Unwind_Context *);
extern _Unwind_Ptr _Unwind_GetRegionStart (struct _Unwind_Context *);
@ -186,6 +205,12 @@ extern _Unwind_Ptr _Unwind_GetDataRelBase (struct _Unwind_Context *);
extern _Unwind_Ptr _Unwind_GetTextRelBase (struct _Unwind_Context *);
#endif
/* @@@ Given an address, return the entry point of the function that
contains it. */
extern void * _Unwind_FindEnclosingFunction (void *pc);
#ifdef __cplusplus
}
#endif
#endif /* unwind.h */

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1997, 1998, 2000, 2001 Free Software Foundation, Inc.
/* Copyright (C) 1997, 1998, 2000, 2001, 2003 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
@ -17,8 +17,10 @@
02111-1307 USA. */
/* Define the machine-dependent type `jmp_buf'. Intel 386 version. */
#ifndef _BITS_SETJMP_H
#define _BITS_SETJMP_H 1
#ifndef _SETJMP_H
#if !defined _SETJMP_H && !defined _PTHREAD_H
# error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
#endif
@ -40,3 +42,5 @@ typedef int __jmp_buf[6];
containing a local variable at ADDRESS. */
#define _JMPBUF_UNWINDS(jmpbuf, address) \
((void *) (address) < (void *) (jmpbuf)[JB_SP])
#endif /* bits/setjmp.h */

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1997, 1998, 2000 Free Software Foundation, Inc.
/* Copyright (C) 1997, 1998, 2000, 2003 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
@ -17,8 +17,10 @@
02111-1307 USA. */
/* Define the machine-dependent type `jmp_buf'. PowerPC version. */
#ifndef _BITS_SETJMP_H
#define _BITS_SETJMP_H 1
#ifndef _SETJMP_H
#if !defined _SETJMP_H && !defined _PTHREAD_H
# error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
#endif
@ -58,3 +60,5 @@ typedef long int __jmp_buf[58];
containing a local variable at ADDRESS. */
#define _JMPBUF_UNWINDS(jmpbuf, address) \
((void *) (address) < (void *) (jmpbuf)[JB_GPR1])
#endif /* bits/setjmp.h */

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
/* Copyright (C) 1999, 2000, 2003 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
@ -17,8 +17,10 @@
02111-1307 USA. */
/* Define the machine-dependent type `jmp_buf'. SH version. */
#ifndef _BITS_SETJMP_H
#define _BITS_SETJMP_H 1
#ifndef _SETJMP_H
#if !defined _SETJMP_H && !defined _PTHREAD_H
# error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
#endif
@ -43,10 +45,12 @@ typedef struct
#endif
#if defined __USE_MISC || defined _ASM
#define JB_SIZE (4 * 15)
# define JB_SIZE (4 * 15)
#endif
/* Test if longjmp to JMPBUF would unwind the frame
containing a local variable at ADDRESS. */
#define _JMPBUF_UNWINDS(jmpbuf, address) \
((void *) (address) < &(jmpbuf)[0].__regs[7])
#endif /* bits/setjmp.h */

View File

@ -164,7 +164,7 @@ __i686.get_pc_thunk.reg: \
# else
/* Store (- %eax) into errno through the GOT. */
# define SYSCALL_ERROR_HANDLER \
0:SETUP_PIC_REG(cx); \
0:SETUP_PIC_REG(cx); \
addl $_GLOBAL_OFFSET_TABLE_, %ecx; \
xorl %edx, %edx; \
subl %eax, %edx; \
@ -250,9 +250,9 @@ __i686.get_pc_thunk.reg: \
#define PUSHARGS_1 movl %ebx, %edx; PUSHARGS_0
#define DOARGS_1 _DOARGS_1 (4)
#define POPARGS_1 POPARGS_0; movl %edx, %ebx
#define _PUSHARGS_1 pushl %ebx; _PUSHARGS_0
#define _PUSHARGS_1 pushl %ebx; L(PUSHBX1): _PUSHARGS_0
#define _DOARGS_1(n) movl n(%esp), %ebx; _DOARGS_0(n-4)
#define _POPARGS_1 _POPARGS_0; popl %ebx
#define _POPARGS_1 _POPARGS_0; popl %ebx; L(POPBX1):
#define PUSHARGS_2 PUSHARGS_1
#define DOARGS_2 _DOARGS_2 (8)
@ -271,16 +271,16 @@ __i686.get_pc_thunk.reg: \
#define PUSHARGS_4 _PUSHARGS_4
#define DOARGS_4 _DOARGS_4 (24)
#define POPARGS_4 _POPARGS_4
#define _PUSHARGS_4 pushl %esi; _PUSHARGS_3
#define _PUSHARGS_4 pushl %esi; L(PUSHSI1): _PUSHARGS_3
#define _DOARGS_4(n) movl n(%esp), %esi; _DOARGS_3 (n-4)
#define _POPARGS_4 _POPARGS_3; popl %esi
#define _POPARGS_4 _POPARGS_3; popl %esi; L(POPSI1):
#define PUSHARGS_5 _PUSHARGS_5
#define DOARGS_5 _DOARGS_5 (32)
#define POPARGS_5 _POPARGS_5
#define _PUSHARGS_5 pushl %edi; _PUSHARGS_4
#define _PUSHARGS_5 pushl %edi; L(PUSHDI1): _PUSHARGS_4
#define _DOARGS_5(n) movl n(%esp), %edi; _DOARGS_4 (n-4)
#define _POPARGS_5 _POPARGS_4; popl %edi
#define _POPARGS_5 _POPARGS_4; popl %edi; L(POPDI1):
#else /* !__ASSEMBLER__ */

View File

@ -1,5 +1,5 @@
/* Define the machine-dependent type `jmp_buf'. Linux/IA-64 version.
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
Copyright (C) 1999, 2000, 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
@ -18,7 +18,10 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef _SETJMP_H
#ifndef _BITS_SETJMP_H
#define _BITS_SETJMP_H 1
#if !defined _SETJMP_H && !defined _PTHREAD_H
# error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
#endif
@ -33,3 +36,5 @@ typedef long __jmp_buf[_JBLEN] __attribute__ ((aligned (16))); /* guarantees 128
variable at ADDRESS. */
#define _JMPBUF_UNWINDS(_jmpbuf, _address) \
((void *)(_address) < (void *)(((long *)_jmpbuf)[0]))
#endif /* bits/setjmp.h */

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
/* Copyright (C) 2001, 2002, 2003 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
@ -17,8 +17,10 @@
02111-1307 USA. */
/* Define the machine-dependent type `jmp_buf'. x86-64 version. */
#ifndef _BITS_SETJMP_H
#define _BITS_SETJMP_H 1
#ifndef _SETJMP_H
#if !defined _SETJMP_H && !defined _PTHREAD_H
# error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
#endif
@ -72,3 +74,5 @@ typedef int __jmp_buf[6];
((void *) (address) < (void *) (jmpbuf)[JB_SP])
# endif
#endif
#endif /* bits/setjmp.h */