aboutsummaryrefslogtreecommitdiff
path: root/nptl/sysdeps
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2003-04-12 00:58:26 +0000
committerUlrich Drepper <drepper@redhat.com>2003-04-12 00:58:26 +0000
commit09d65ff393e9183eecba1e5cb877e95dbdd3d4a4 (patch)
treeb618ac607f17c1d683f1ea1e4d34415e4ea8e7f8 /nptl/sysdeps
parent877e51b20f69ce1927c4978134d0c2afbbf856ad (diff)
downloadglibc-09d65ff393e9183eecba1e5cb877e95dbdd3d4a4.tar
glibc-09d65ff393e9183eecba1e5cb877e95dbdd3d4a4.tar.gz
glibc-09d65ff393e9183eecba1e5cb877e95dbdd3d4a4.tar.bz2
glibc-09d65ff393e9183eecba1e5cb877e95dbdd3d4a4.zip
Update.
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.
Diffstat (limited to 'nptl/sysdeps')
-rw-r--r--nptl/sysdeps/pthread/bits/libc-lock.h13
-rwxr-xr-xnptl/sysdeps/pthread/configure55
-rw-r--r--nptl/sysdeps/pthread/configure.in13
-rw-r--r--nptl/sysdeps/pthread/pthread-functions.h2
-rw-r--r--nptl/sysdeps/pthread/pthread.h103
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h263
7 files changed, 416 insertions, 36 deletions
diff --git a/nptl/sysdeps/pthread/bits/libc-lock.h b/nptl/sysdeps/pthread/bits/libc-lock.h
index 3a3d3cc6d3..945a81cb82 100644
--- a/nptl/sysdeps/pthread/bits/libc-lock.h
+++ b/nptl/sysdeps/pthread/bits/libc-lock.h
@@ -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; \
diff --git a/nptl/sysdeps/pthread/configure b/nptl/sysdeps/pthread/configure
index 8999d37e5a..50293a4f1c 100755
--- a/nptl/sysdeps/pthread/configure
+++ b/nptl/sysdeps/pthread/configure
@@ -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
diff --git a/nptl/sysdeps/pthread/configure.in b/nptl/sysdeps/pthread/configure.in
index 8350f86dc0..e4ea6830d6 100644
--- a/nptl/sysdeps/pthread/configure.in
+++ b/nptl/sysdeps/pthread/configure.in
@@ -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
diff --git a/nptl/sysdeps/pthread/pthread-functions.h b/nptl/sysdeps/pthread/pthread-functions.h
index 9f38e34053..93ba089982 100644
--- a/nptl/sysdeps/pthread/pthread-functions.h
+++ b/nptl/sysdeps/pthread/pthread-functions.h
@@ -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. */
diff --git a/nptl/sysdeps/pthread/pthread.h b/nptl/sysdeps/pthread/pthread.h
index 72673d11a6..5373b80dcf 100644
--- a/nptl/sysdeps/pthread/pthread.h
+++ b/nptl/sysdeps/pthread/pthread.h
@@ -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,43 +406,83 @@ 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)); }
+# 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
-extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
- int __execute) __THROW;
+/* 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. */
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
index c14f1b1ef6..0834894c25 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
@@ -149,4 +149,7 @@ typedef union
#endif
+/* Extra attributes for the cleanup functions. */
+#define __cleanup_fct_attribute __attribute ((regparm (1)))
+
#endif /* bits/pthreadtypes.h */
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h b/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h
index 35f05e1cc2..b7009d753f 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h
+++ b/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h
@@ -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 \