mirror of
git://sourceware.org/git/glibc.git
synced 2025-02-17 13:00:43 +08:00
Update.
2003-11-05 Jakub Jelinek <jakub@redhat.com> * unwind.c (FRAME_LEFT): Define. (unwind_stop): Handle old style cleanups here. (__pthread_unwind): Handle old style cleanups only if !HAVE_FORCED_UNWIND. * Makefile (tests): Add tst-cleanup4 and tst-cleanupx4. (CFLAGS-tst-cleanupx4.c): Add -fexceptions. ($(objpfx)tst-cleanup4): Depend on $(objpfx)tst-cleanup4aux.o. ($(objpfx)tst-cleanupx4): Likewise. * tst-cleanup4.c: New test. * tst-cleanup4aux.c: New. * tst-cleanupx4.c: New test.
This commit is contained in:
parent
c28422b575
commit
44e941492d
@ -1,3 +1,17 @@
|
||||
2003-11-05 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* unwind.c (FRAME_LEFT): Define.
|
||||
(unwind_stop): Handle old style cleanups here.
|
||||
(__pthread_unwind): Handle old style cleanups only if
|
||||
!HAVE_FORCED_UNWIND.
|
||||
* Makefile (tests): Add tst-cleanup4 and tst-cleanupx4.
|
||||
(CFLAGS-tst-cleanupx4.c): Add -fexceptions.
|
||||
($(objpfx)tst-cleanup4): Depend on $(objpfx)tst-cleanup4aux.o.
|
||||
($(objpfx)tst-cleanupx4): Likewise.
|
||||
* tst-cleanup4.c: New test.
|
||||
* tst-cleanup4aux.c: New.
|
||||
* tst-cleanupx4.c: New test.
|
||||
|
||||
2003-11-04 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* sysdeps/pthread/bits/stdio-lock.h: Use lll_*lock instead of
|
||||
|
@ -216,7 +216,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 \
|
||||
tst-cancel6 tst-cancel7 tst-cancel8 tst-cancel9 tst-cancel10 \
|
||||
tst-cancel11 tst-cancel12 tst-cancel13 tst-cancel14 tst-cancel15 \
|
||||
tst-cancel16 tst-cancel17 tst-cancel18 tst-cancel19 \
|
||||
tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 \
|
||||
tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 tst-cleanup4 \
|
||||
tst-flock1 tst-flock2 \
|
||||
tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \
|
||||
tst-signal6 \
|
||||
@ -248,7 +248,7 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \
|
||||
tst-cancelx6 tst-cancelx7 tst-cancelx8 tst-cancelx9 tst-cancelx10 \
|
||||
tst-cancelx11 tst-cancelx12 tst-cancelx13 tst-cancelx14 tst-cancelx15\
|
||||
tst-cancelx16 tst-cancelx17 tst-cancelx18 \
|
||||
tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3 \
|
||||
tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3 tst-cleanupx4 \
|
||||
tst-oncex3 tst-oncex4
|
||||
endif
|
||||
ifeq ($(build-shared),yes)
|
||||
@ -393,6 +393,7 @@ CFLAGS-tst-cleanupx0.c += -fexceptions -fasynchronous-unwind-tables
|
||||
CFLAGS-tst-cleanupx1.c += -fexceptions -fasynchronous-unwind-tables
|
||||
CFLAGS-tst-cleanupx2.c += -fexceptions
|
||||
CFLAGS-tst-cleanupx3.c += -fexceptions
|
||||
CFLAGS-tst-cleanupx4.c += -fexceptions
|
||||
CFLAGS-tst-oncex3.c += -fexceptions
|
||||
CFLAGS-tst-oncex4.c += -fexceptions
|
||||
CFLAGS-tst-align.c += $(stack-align-test-flags)
|
||||
@ -405,6 +406,9 @@ LDFLAGS-tst-atfork2 = -rdynamic
|
||||
tst-atfork2-ENV = MALLOC_TRACE=$(objpfx)tst-atfork2.mtrace
|
||||
$(objpfx)tst-atfork2mod.so: $(shared-thread-library)
|
||||
|
||||
$(objpfx)tst-cleanup4: $(objpfx)tst-cleanup4aux.o $(shared-thread-library)
|
||||
$(objpfx)tst-cleanupx4: $(objpfx)tst-cleanup4aux.o $(shared-thread-library)
|
||||
|
||||
$(objpfx)tst-tls3: $(libdl) $(shared-thread-library)
|
||||
LDFLAGS-tst-tls3 = -rdynamic
|
||||
$(objpfx)tst-tls3.out: $(objpfx)tst-tls3mod.so
|
||||
|
198
nptl/tst-cleanup4.c
Normal file
198
nptl/tst-cleanup4.c
Normal file
@ -0,0 +1,198 @@
|
||||
/* Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Jakub Jelinek <jakub@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 <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* LinuxThreads pthread_cleanup_{push,pop} helpers. */
|
||||
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);
|
||||
|
||||
static int fds[2];
|
||||
static pthread_barrier_t b2;
|
||||
static int global;
|
||||
|
||||
/* Defined in tst-cleanup4aux.c, never compiled with -fexceptions. */
|
||||
extern void fn5 (void);
|
||||
extern void fn7 (void);
|
||||
extern void fn9 (void);
|
||||
|
||||
void
|
||||
clh (void *arg)
|
||||
{
|
||||
int val = (long int) arg;
|
||||
|
||||
printf ("clh (%d)\n", val);
|
||||
|
||||
global *= val;
|
||||
global += val;
|
||||
}
|
||||
|
||||
|
||||
static __attribute__((noinline)) void
|
||||
fn_read (void)
|
||||
{
|
||||
int r = pthread_barrier_wait (&b2);
|
||||
if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
{
|
||||
printf ("%s: barrier_wait failed\n", __FUNCTION__);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
char c;
|
||||
read (fds[0], &c, 1);
|
||||
}
|
||||
|
||||
|
||||
__attribute__((noinline)) void
|
||||
fn0 (void)
|
||||
{
|
||||
pthread_cleanup_push (clh, (void *) 1l);
|
||||
|
||||
fn_read ();
|
||||
|
||||
pthread_cleanup_pop (1);
|
||||
}
|
||||
|
||||
|
||||
__attribute__((noinline)) void
|
||||
fn1 (void)
|
||||
{
|
||||
/* This is the old LinuxThreads pthread_cleanup_{push,pop}. */
|
||||
struct _pthread_cleanup_buffer b;
|
||||
_pthread_cleanup_push (&b, clh, (void *) 2l);
|
||||
|
||||
fn0 ();
|
||||
|
||||
_pthread_cleanup_pop (&b, 1);
|
||||
}
|
||||
|
||||
|
||||
static __attribute__((noinline)) void
|
||||
fn2 (void)
|
||||
{
|
||||
pthread_cleanup_push (clh, (void *) 3l);
|
||||
|
||||
fn1 ();
|
||||
|
||||
pthread_cleanup_pop (1);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
tf (void *a)
|
||||
{
|
||||
switch ((long) a)
|
||||
{
|
||||
case 0:
|
||||
fn2 ();
|
||||
break;
|
||||
case 1:
|
||||
fn5 ();
|
||||
break;
|
||||
case 2:
|
||||
fn7 ();
|
||||
break;
|
||||
case 3:
|
||||
fn9 ();
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
do_test (void)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (pipe (fds) != 0)
|
||||
{
|
||||
puts ("pipe failed");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (pthread_barrier_init (&b2, NULL, 2) != 0)
|
||||
{
|
||||
puts ("b2 init failed");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
const int expect[] =
|
||||
{
|
||||
15, /* 1 2 3 */
|
||||
276, /* 1 4 5 6 */
|
||||
120, /* 1 7 8 */
|
||||
460 /* 1 2 9 10 */
|
||||
};
|
||||
|
||||
long i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
global = 0;
|
||||
|
||||
printf ("test %ld\n", i);
|
||||
|
||||
pthread_t th;
|
||||
if (pthread_create (&th, NULL, tf, (void *) i) != 0)
|
||||
{
|
||||
puts ("create failed");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
int e = pthread_barrier_wait (&b2);
|
||||
if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
{
|
||||
printf ("%s: barrier_wait failed\n", __FUNCTION__);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
pthread_cancel (th);
|
||||
|
||||
void *r;
|
||||
if ((e = pthread_join (th, &r)) != 0)
|
||||
{
|
||||
printf ("join failed: %d\n", e);
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
if (r != PTHREAD_CANCELED)
|
||||
{
|
||||
puts ("thread not canceled");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (global != expect[i])
|
||||
{
|
||||
printf ("global = %d, expected %d\n", global, expect[i]);
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
121
nptl/tst-cleanup4aux.c
Normal file
121
nptl/tst-cleanup4aux.c
Normal file
@ -0,0 +1,121 @@
|
||||
/* Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Jakub Jelinek <jakub@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 <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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 clh (void *arg);
|
||||
extern void fn0 (void);
|
||||
extern void fn1 (void);
|
||||
extern void fn5 (void);
|
||||
extern void fn7 (void);
|
||||
extern void fn9 (void);
|
||||
|
||||
|
||||
static __attribute__((noinline)) void
|
||||
fn3 (void)
|
||||
{
|
||||
/* This is the old LinuxThreads pthread_cleanup_{push,pop}. */
|
||||
struct _pthread_cleanup_buffer b;
|
||||
_pthread_cleanup_push (&b, clh, (void *) 4l);
|
||||
|
||||
fn0 ();
|
||||
|
||||
_pthread_cleanup_pop (&b, 1);
|
||||
}
|
||||
|
||||
|
||||
static __attribute__((noinline)) void
|
||||
fn4 (void)
|
||||
{
|
||||
pthread_cleanup_push (clh, (void *) 5l);
|
||||
|
||||
fn3 ();
|
||||
|
||||
pthread_cleanup_pop (1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
fn5 (void)
|
||||
{
|
||||
/* This is the old LinuxThreads pthread_cleanup_{push,pop}. */
|
||||
struct _pthread_cleanup_buffer b;
|
||||
_pthread_cleanup_push (&b, clh, (void *) 6l);
|
||||
|
||||
fn4 ();
|
||||
|
||||
_pthread_cleanup_pop (&b, 1);
|
||||
}
|
||||
|
||||
|
||||
static __attribute__((noinline)) void
|
||||
fn6 (void)
|
||||
{
|
||||
pthread_cleanup_push (clh, (void *) 7l);
|
||||
|
||||
fn0 ();
|
||||
|
||||
pthread_cleanup_pop (1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
fn7 (void)
|
||||
{
|
||||
/* This is the old LinuxThreads pthread_cleanup_{push,pop}. */
|
||||
struct _pthread_cleanup_buffer b;
|
||||
_pthread_cleanup_push (&b, clh, (void *) 8l);
|
||||
|
||||
fn6 ();
|
||||
|
||||
_pthread_cleanup_pop (&b, 1);
|
||||
}
|
||||
|
||||
|
||||
static __attribute__((noinline)) void
|
||||
fn8 (void)
|
||||
{
|
||||
pthread_cleanup_push (clh, (void *) 9l);
|
||||
|
||||
fn1 ();
|
||||
|
||||
pthread_cleanup_pop (1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
fn9 (void)
|
||||
{
|
||||
/* This is the old LinuxThreads pthread_cleanup_{push,pop}. */
|
||||
struct _pthread_cleanup_buffer b;
|
||||
_pthread_cleanup_push (&b, clh, (void *) 10l);
|
||||
|
||||
fn8 ();
|
||||
|
||||
_pthread_cleanup_pop (&b, 1);
|
||||
}
|
1
nptl/tst-cleanupx4.c
Normal file
1
nptl/tst-cleanupx4.c
Normal file
@ -0,0 +1 @@
|
||||
#include "tst-cleanup4.c"
|
@ -27,6 +27,14 @@
|
||||
|
||||
#ifdef HAVE_FORCED_UNWIND
|
||||
|
||||
#ifdef _STACK_GROWS_DOWN
|
||||
# define FRAME_LEFT(frame, other) ((char *) frame >= (char *) other)
|
||||
#elif _STACK_GROWS_UP
|
||||
# define FRAME_LEFT(frame, other) ((char *) frame <= (char *) other)
|
||||
#else
|
||||
# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
|
||||
#endif
|
||||
|
||||
static _Unwind_Reason_Code
|
||||
unwind_stop (int version, _Unwind_Action actions,
|
||||
_Unwind_Exception_Class exc_class,
|
||||
@ -34,6 +42,9 @@ unwind_stop (int version, _Unwind_Action actions,
|
||||
struct _Unwind_Context *context, void *stop_parameter)
|
||||
{
|
||||
struct pthread_unwind_buf *buf = stop_parameter;
|
||||
struct pthread *self = THREAD_SELF;
|
||||
struct _pthread_cleanup_buffer *curp = THREAD_GETMEM (self, cleanup);
|
||||
int do_longjump = 0;
|
||||
|
||||
/* 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
|
||||
@ -42,6 +53,37 @@ unwind_stop (int version, _Unwind_Action actions,
|
||||
previous frame. */
|
||||
if ((actions & _UA_END_OF_STACK)
|
||||
|| ! _JMPBUF_CFA_UNWINDS (buf->cancel_jmp_buf[0].jmp_buf, context))
|
||||
do_longjump = 1;
|
||||
|
||||
if (__builtin_expect (curp != NULL, 0))
|
||||
{
|
||||
/* Handle the compatibility stuff. Execute all handlers
|
||||
registered with the old method which would be unwound by this
|
||||
step. */
|
||||
struct _pthread_cleanup_buffer *oldp = buf->priv.data.cleanup;
|
||||
void *cfa = (void *) _Unwind_GetCFA (context);
|
||||
|
||||
if (curp != oldp && (do_longjump || FRAME_LEFT (cfa, curp)))
|
||||
{
|
||||
do
|
||||
{
|
||||
/* Pointer to the next element. */
|
||||
struct _pthread_cleanup_buffer *nextp = curp->__prev;
|
||||
|
||||
/* Call the handler. */
|
||||
curp->__routine (curp->__arg);
|
||||
|
||||
/* To the next. */
|
||||
curp = nextp;
|
||||
}
|
||||
while (curp != oldp && (do_longjump || FRAME_LEFT (cfa, curp)));
|
||||
|
||||
/* Mark the current element as handled. */
|
||||
THREAD_SETMEM (self, cleanup, curp);
|
||||
}
|
||||
}
|
||||
|
||||
if (do_longjump)
|
||||
__libc_longjmp ((struct __jmp_buf_tag *) buf->cancel_jmp_buf, 1);
|
||||
|
||||
return _URC_NO_REASON;
|
||||
@ -70,6 +112,14 @@ __pthread_unwind (__pthread_unwind_buf_t *buf)
|
||||
struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
|
||||
struct pthread *self = THREAD_SELF;
|
||||
|
||||
#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. */
|
||||
THREAD_SETMEM (self, exc.exception_class, 0);
|
||||
THREAD_SETMEM (self, exc.exception_cleanup, unwind_cleanup);
|
||||
|
||||
_Unwind_ForcedUnwind (&self->exc, unwind_stop, ibuf);
|
||||
#else
|
||||
/* 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. */
|
||||
@ -95,14 +145,6 @@ __pthread_unwind (__pthread_unwind_buf_t *buf)
|
||||
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. */
|
||||
THREAD_SETMEM (self, exc.exception_class, 0);
|
||||
THREAD_SETMEM (self, exc.exception_cleanup, unwind_cleanup);
|
||||
|
||||
_Unwind_ForcedUnwind (&self->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
|
||||
|
Loading…
Reference in New Issue
Block a user