1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-08-01 10:06:57 +03:00
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:
Ulrich Drepper
2003-11-06 04:29:42 +00:00
parent c28422b575
commit 44e941492d
6 changed files with 390 additions and 10 deletions

View File

@ -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> 2003-11-04 Ulrich Drepper <drepper@redhat.com>
* sysdeps/pthread/bits/stdio-lock.h: Use lll_*lock instead of * sysdeps/pthread/bits/stdio-lock.h: Use lll_*lock instead of

View File

@ -216,7 +216,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 \
tst-cancel6 tst-cancel7 tst-cancel8 tst-cancel9 tst-cancel10 \ tst-cancel6 tst-cancel7 tst-cancel8 tst-cancel9 tst-cancel10 \
tst-cancel11 tst-cancel12 tst-cancel13 tst-cancel14 tst-cancel15 \ tst-cancel11 tst-cancel12 tst-cancel13 tst-cancel14 tst-cancel15 \
tst-cancel16 tst-cancel17 tst-cancel18 tst-cancel19 \ 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-flock1 tst-flock2 \
tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \ tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \
tst-signal6 \ 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-cancelx6 tst-cancelx7 tst-cancelx8 tst-cancelx9 tst-cancelx10 \
tst-cancelx11 tst-cancelx12 tst-cancelx13 tst-cancelx14 tst-cancelx15\ tst-cancelx11 tst-cancelx12 tst-cancelx13 tst-cancelx14 tst-cancelx15\
tst-cancelx16 tst-cancelx17 tst-cancelx18 \ 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 tst-oncex3 tst-oncex4
endif endif
ifeq ($(build-shared),yes) 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-cleanupx1.c += -fexceptions -fasynchronous-unwind-tables
CFLAGS-tst-cleanupx2.c += -fexceptions CFLAGS-tst-cleanupx2.c += -fexceptions
CFLAGS-tst-cleanupx3.c += -fexceptions CFLAGS-tst-cleanupx3.c += -fexceptions
CFLAGS-tst-cleanupx4.c += -fexceptions
CFLAGS-tst-oncex3.c += -fexceptions CFLAGS-tst-oncex3.c += -fexceptions
CFLAGS-tst-oncex4.c += -fexceptions CFLAGS-tst-oncex4.c += -fexceptions
CFLAGS-tst-align.c += $(stack-align-test-flags) 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 tst-atfork2-ENV = MALLOC_TRACE=$(objpfx)tst-atfork2.mtrace
$(objpfx)tst-atfork2mod.so: $(shared-thread-library) $(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) $(objpfx)tst-tls3: $(libdl) $(shared-thread-library)
LDFLAGS-tst-tls3 = -rdynamic LDFLAGS-tst-tls3 = -rdynamic
$(objpfx)tst-tls3.out: $(objpfx)tst-tls3mod.so $(objpfx)tst-tls3.out: $(objpfx)tst-tls3mod.so

198
nptl/tst-cleanup4.c Normal file
View 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
View 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
View File

@ -0,0 +1 @@
#include "tst-cleanup4.c"

View File

@ -27,6 +27,14 @@
#ifdef HAVE_FORCED_UNWIND #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 static _Unwind_Reason_Code
unwind_stop (int version, _Unwind_Action actions, unwind_stop (int version, _Unwind_Action actions,
_Unwind_Exception_Class exc_class, _Unwind_Exception_Class exc_class,
@ -34,6 +42,9 @@ unwind_stop (int version, _Unwind_Action actions,
struct _Unwind_Context *context, void *stop_parameter) struct _Unwind_Context *context, void *stop_parameter)
{ {
struct pthread_unwind_buf *buf = 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". /* 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 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. */ previous frame. */
if ((actions & _UA_END_OF_STACK) if ((actions & _UA_END_OF_STACK)
|| ! _JMPBUF_CFA_UNWINDS (buf->cancel_jmp_buf[0].jmp_buf, context)) || ! _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); __libc_longjmp ((struct __jmp_buf_tag *) buf->cancel_jmp_buf, 1);
return _URC_NO_REASON; 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_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
struct pthread *self = THREAD_SELF; 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 /* Handle the compatibility stuff first. Execute all handlers
registered with the old method. We don't execute them in order, registered with the old method. We don't execute them in order,
instead, they will run first. */ instead, they will run first. */
@ -95,14 +145,6 @@ __pthread_unwind (__pthread_unwind_buf_t *buf)
THREAD_SETMEM (self, cleanup, curp); 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. */ /* We simply jump to the registered setjmp buffer. */
__libc_longjmp ((struct __jmp_buf_tag *) ibuf->cancel_jmp_buf, 1); __libc_longjmp ((struct __jmp_buf_tag *) ibuf->cancel_jmp_buf, 1);
#endif #endif