2001-04-10  Martin Schwidefsky  <schwidefsky@de.ibm.com>

	* sysdeps/unix/sysv/linux/s390/s390-32/getcontext.S: Fix return
	value of getcontext.
	* sysdeps/unix/sysv/linux/s390/s390-64/getcontext.S: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/setcontext.S: Fix return
	value of setcontext.
	* sysdeps/unix/sysv/linux/s390/s390-64/setcontext.S: Likewise.
	* sysdeps/unix/sysv/linux/s390/swapcontext.c: Skip setcontext
	call by changing the saved context.
This commit is contained in:
Ulrich Drepper 2001-04-10 21:46:48 +00:00
parent bf9d1166a0
commit 58f46c794a
18 changed files with 281 additions and 39 deletions

View File

@ -1,3 +1,14 @@
2001-04-10 Martin Schwidefsky <schwidefsky@de.ibm.com>
* sysdeps/unix/sysv/linux/s390/s390-32/getcontext.S: Fix return
value of getcontext.
* sysdeps/unix/sysv/linux/s390/s390-64/getcontext.S: Likewise.
* sysdeps/unix/sysv/linux/s390/s390-32/setcontext.S: Fix return
value of setcontext.
* sysdeps/unix/sysv/linux/s390/s390-64/setcontext.S: Likewise.
* sysdeps/unix/sysv/linux/s390/swapcontext.c: Skip setcontext
call by changing the saved context.
2001-04-10 Ulrich Drepper <drepper@redhat.com>
* sysdeps/alpha/stackinfo.h: New file.

View File

@ -1,3 +1,36 @@
2001-04-10 Ulrich Drepper <drepper@redhat.com>
* join.c (pthread_exit): Move code to new function __pthread_do_exit
which takes an extra parameter with the current frame pointer.
Call new function with CURRENT_STACK_FRAME.
(__pthread_do_exit): New function. Call __pthread_perform_cleanup
with the new parameter.
(pthread_join): Call __pthread_do_exit instead of pthread_exit.
* cancel.c (__pthread_perform_cleanup): Takes extra parameter. Use
this parameter as the initial value the cleanup handler records are
compared against. No active cleanup handler record must have an
address lower than the previous one and the initial record must be
above (below on PA) the frame address passed in.
(pthread_setcancelstate): Call __pthread_do_exit instead of
pthread_exit.
(pthread_setcanceltype): Likewise.
(pthread_testcancel): Likewise.
(_pthread_cleanup_pop_restore): Likewise.
* condvar.c (pthread_cond_wait): Likewise.
(pthread_cond_timedwait_relative): Likewise.
* manager.c (pthread_start_thread): Likewise.
* oldsemaphore.c (__old_sem_wait): Likewise.
* pthread.c (pthread_handle_sigcancel): Likewise.
* semaphore.c (__new_sem_wait): Likewise.
(sem_timedwait): Likewise.
* ptlongjmp.c (pthread_cleanup_upto): Also use current stack frame
to limit the cleanup handlers which get run.
* internals.h: Add prototype for __pthread_do_exit. Adjust prototype
for __pthread_perform_cleanup.
* Makefile (tests): Add tst-cancel.
* tst-cancel.c: New file.
2001-04-08 Hans-Peter Nilsson <hp@axis.com>
* sysdeps/cris/pt-machine.h: New file.

View File

@ -56,7 +56,7 @@ endif
librt-tests = ex10 ex11
tests = ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 $(librt-tests) ex12 ex13 joinrace \
tststack $(tests-nodelete-$(have-z-nodelete)) ecmutex ex14 ex15 ex16 \
ex17
ex17 tst-cancel
ifeq (yes,$(build-shared))
tests-nodelete-yes = unload

View File

@ -20,6 +20,9 @@
#include "internals.h"
#include "spinlock.h"
#include "restart.h"
#include <stackinfo.h>
#include <stdio.h>
int pthread_setcancelstate(int state, int * oldstate)
{
@ -31,7 +34,7 @@ int pthread_setcancelstate(int state, int * oldstate)
if (THREAD_GETMEM(self, p_canceled) &&
THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE &&
THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
pthread_exit(PTHREAD_CANCELED);
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
return 0;
}
@ -45,7 +48,7 @@ int pthread_setcanceltype(int type, int * oldtype)
if (THREAD_GETMEM(self, p_canceled) &&
THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE &&
THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
pthread_exit(PTHREAD_CANCELED);
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
return 0;
}
@ -112,7 +115,7 @@ void pthread_testcancel(void)
pthread_descr self = thread_self();
if (THREAD_GETMEM(self, p_canceled)
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)
pthread_exit(PTHREAD_CANCELED);
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
}
void _pthread_cleanup_push(struct _pthread_cleanup_buffer * buffer,
@ -155,15 +158,27 @@ void _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer * buffer,
if (THREAD_GETMEM(self, p_canceled) &&
THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE &&
THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
pthread_exit(PTHREAD_CANCELED);
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
}
void __pthread_perform_cleanup(void)
void __pthread_perform_cleanup(char *currentframe)
{
pthread_descr self = thread_self();
struct _pthread_cleanup_buffer * c;
for (c = THREAD_GETMEM(self, p_cleanup); c != NULL; c = c->__prev)
c->__routine(c->__arg);
{
#if _STACK_GROWS_DOWN
if ((char *) c <= currentframe)
break;
#elif _STACK_GROWS_UP
if ((char *) c >= currentframe)
break;
#else
# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
#endif
c->__routine(c->__arg);
}
/* And the TSD which needs special help. */
if (THREAD_GETMEM(self, p_libc_specific[_LIBC_TSD_KEY_RPC_VARS]) != NULL)

View File

@ -93,7 +93,7 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
if (already_canceled) {
__pthread_set_own_extricate_if(self, 0);
pthread_exit(PTHREAD_CANCELED);
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
}
pthread_mutex_unlock(mutex);
@ -122,7 +122,7 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
THREAD_SETMEM(self, p_woken_by_cancel, 0);
pthread_mutex_lock(mutex);
pthread_exit(PTHREAD_CANCELED);
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
}
/* Put back any resumes we caught that don't belong to us. */
@ -168,7 +168,7 @@ pthread_cond_timedwait_relative(pthread_cond_t *cond,
if (already_canceled) {
__pthread_set_own_extricate_if(self, 0);
pthread_exit(PTHREAD_CANCELED);
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
}
pthread_mutex_unlock(mutex);
@ -216,7 +216,7 @@ pthread_cond_timedwait_relative(pthread_cond_t *cond,
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
THREAD_SETMEM(self, p_woken_by_cancel, 0);
pthread_mutex_lock(mutex);
pthread_exit(PTHREAD_CANCELED);
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
}
/* Put back any resumes we caught that don't belong to us. */

View File

@ -428,8 +428,10 @@ static inline pthread_descr thread_self (void)
/* Internal global functions */
extern void __pthread_do_exit (void *retval, char *currentframe)
__attribute__ ((__noreturn__));
extern void __pthread_destroy_specifics (void);
extern void __pthread_perform_cleanup (void);
extern void __pthread_perform_cleanup (char *currentframe);
extern void __pthread_init_max_stacksize (void);
extern int __pthread_initialize_manager (void);
extern void __pthread_message (char * fmt, ...);

View File

@ -24,6 +24,11 @@
#include "restart.h"
void pthread_exit(void * retval)
{
__pthread_do_exit (retval, CURRENT_STACK_FRAME);
}
void __pthread_do_exit(void *retval, char *currentframe)
{
pthread_descr self = thread_self();
pthread_descr joining;
@ -33,7 +38,7 @@ void pthread_exit(void * retval)
contain cancellation points */
THREAD_SETMEM(self, p_canceled, 0);
/* Call cleanup functions and destroy the thread-specific data */
__pthread_perform_cleanup();
__pthread_perform_cleanup(currentframe);
__pthread_destroy_specifics();
/* Store return value */
__pthread_lock(THREAD_GETMEM(self, p_lock), self);
@ -144,7 +149,7 @@ int pthread_join(pthread_t thread_id, void ** thread_return)
if (already_canceled) {
__pthread_set_own_extricate_if(self, 0);
pthread_exit(PTHREAD_CANCELED);
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
}
suspend(self);
@ -155,7 +160,7 @@ int pthread_join(pthread_t thread_id, void ** thread_return)
if (THREAD_GETMEM(self, p_woken_by_cancel)
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
THREAD_SETMEM(self, p_woken_by_cancel, 0);
pthread_exit(PTHREAD_CANCELED);
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
}
__pthread_lock(&handle->h_lock, self);
}

View File

@ -262,7 +262,7 @@ static int pthread_start_thread(void *arg)
outcome = self->p_start_args.start_routine(THREAD_GETMEM(self,
p_start_args.arg));
/* Exit with the given return value */
pthread_exit(outcome);
__pthread_do_exit(outcome, CURRENT_STACK_FRAME);
return 0;
}

View File

@ -144,7 +144,7 @@ int __old_sem_wait(old_sem_t * sem)
}
}
}
pthread_exit(PTHREAD_CANCELED);
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
}
}
}

View File

@ -817,7 +817,7 @@ static void pthread_handle_sigcancel(int sig)
if (__builtin_expect (THREAD_GETMEM(self, p_canceled), 0)
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
if (THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
pthread_exit(PTHREAD_CANCELED);
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
jmpbuf = THREAD_GETMEM(self, p_cancel_jmp);
if (jmpbuf != NULL) {
THREAD_SETMEM(self, p_cancel_jmp, NULL);

View File

@ -18,6 +18,7 @@
#include <setjmp.h>
#include "pthread.h"
#include "internals.h"
#include <stackinfo.h>
/* These functions are not declared anywhere since they shouldn't be
used at another place but here. */
@ -31,11 +32,29 @@ static void pthread_cleanup_upto(__jmp_buf target)
{
pthread_descr self = thread_self();
struct _pthread_cleanup_buffer * c;
char *currentframe = CURRENT_STACK_FRAME;
for (c = THREAD_GETMEM(self, p_cleanup);
c != NULL && _JMPBUF_UNWINDS(target, c);
c = c->__prev)
c->__routine(c->__arg);
{
#if _STACK_GROWS_DOWN
if ((char *) c <= currentframe)
{
c = NULL;
break;
}
#elif _STACK_GROWS_UP
if ((char *) c >= currentframe)
{
c = NULL;
break;
}
#else
# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
#endif
c->__routine(c->__arg);
}
THREAD_SETMEM(self, p_cleanup, c);
if (THREAD_GETMEM(self, p_in_sighandler)
&& _JMPBUF_UNWINDS(target, THREAD_GETMEM(self, p_in_sighandler)))

View File

@ -85,7 +85,7 @@ int __new_sem_wait(sem_t * sem)
if (already_canceled) {
__pthread_set_own_extricate_if(self, 0);
pthread_exit(PTHREAD_CANCELED);
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
}
/* Wait for sem_post or cancellation, or fall through if already canceled */
@ -111,7 +111,7 @@ int __new_sem_wait(sem_t * sem)
if (THREAD_GETMEM(self, p_woken_by_cancel)
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
THREAD_SETMEM(self, p_woken_by_cancel, 0);
pthread_exit(PTHREAD_CANCELED);
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
}
/* We got the semaphore */
return 0;
@ -245,7 +245,7 @@ int sem_timedwait(sem_t *sem, const struct timespec *abstime)
if (already_canceled) {
__pthread_set_own_extricate_if(self, 0);
pthread_exit(PTHREAD_CANCELED);
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
}
spurious_wakeup_count = 0;
@ -289,7 +289,7 @@ int sem_timedwait(sem_t *sem, const struct timespec *abstime)
if (THREAD_GETMEM(self, p_woken_by_cancel)
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
THREAD_SETMEM(self, p_woken_by_cancel, 0);
pthread_exit(PTHREAD_CANCELED);
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
}
/* We got the semaphore */
return 0;

153
linuxthreads/tst-cancel.c Normal file
View File

@ -0,0 +1,153 @@
/* Tests for cancelation handling. */
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
int fd;
pthread_barrier_t bar;
static void
cleanup (void *arg)
{
int nr = (int) (long int) arg;
char s[30];
char *cp = stpcpy (s, "cleanup ");
*cp++ = '0' + nr;
*cp++ = '\n';
__libc_write (fd, s, cp - s);
}
static void *
t1 (void *arg)
{
pthread_cleanup_push (cleanup, (void *) (long int) 1);
return NULL;
pthread_cleanup_pop (0);
}
static void
inner (int a)
{
pthread_cleanup_push (cleanup, (void *) (long int) a);
if (a)
return;
pthread_cleanup_pop (0);
}
static void *
t2 (void *arg)
{
pthread_cleanup_push (cleanup, (void *) (long int) 2);
inner ((int) (long int) arg);
return NULL;
pthread_cleanup_pop (0);
}
static void *
t3 (void *arg)
{
pthread_cleanup_push (cleanup, (void *) (long int) 4);
inner ((int) (long int) arg);
pthread_exit (NULL);
pthread_cleanup_pop (0);
}
int
main (void)
{
pthread_t td;
int err;
char tmp[] = "thtstXXXXXX";
struct stat64 st;
int result = 0;
fd = mkstemp (tmp);
if (fd == -1)
{
printf ("cannot create temporary file: %m");
exit (1);
}
unlink (tmp);
err = pthread_barrier_init (&bar, NULL, 2);
if (err != 0 )
{
printf ("cannot create barrier: %s\n", strerror (err));
exit (1);
}
err = pthread_create (&td, NULL, t1, NULL);
if (err != 0)
{
printf ("cannot create thread t1: %s\n", strerror (err));
exit (1);
}
err = pthread_join (td, NULL);
if (err != 0)
{
printf ("cannot join thread: %s\n", strerror (err));
exit (1);
}
err = pthread_create (&td, NULL, t2, (void *) 3);
if (err != 0)
{
printf ("cannot create thread t2: %s\n", strerror (err));
exit (1);
}
err = pthread_join (td, NULL);
if (err != 0)
{
printf ("cannot join thread: %s\n", strerror (err));
exit (1);
}
err = pthread_create (&td, NULL, t3, (void *) 5);
if (err != 0)
{
printf ("cannot create thread t3: %s\n", strerror (err));
exit (1);
}
err = pthread_join (td, NULL);
if (err != 0)
{
printf ("cannot join thread: %s\n", strerror (err));
exit (1);
}
if (fstat64 (fd, &st) < 0)
{
printf ("cannot stat temporary file: %m\n");
result = 1;
}
else if (st.st_size != 0)
{
char buf[512];
puts ("some cleanup handlers ran:");
fflush (stdout);
while (1)
{
ssize_t n = read (fd, buf, sizeof buf);
if (n < 0)
break;
write (STDOUT_FILENO, buf, n);
}
result = 1;
}
return result;
}

View File

@ -25,9 +25,7 @@
/* __getcontext (const ucontext_t *ucp)
Saves the machine context in UCP such that when it is activated,
it appears as if __getcontext() returned again. The only difference
is that on a first return, %r2 contains 1 and on a subsequent
return, it contains 0.
it appears as if __getcontext() returned again.
This implementation is intended to be used for *synchronous* context
switches only. Therefore, it does not have to save anything
@ -61,11 +59,13 @@ ENTRY(__getcontext)
std %f14,SC_FPRS+112(%r5)
std %f15,SC_FPRS+120(%r5)
/* Set __getcontext return value to 0. */
slr %r2,%r2
/* Store general purpose registers. */
stm %r0,%r15,SC_GPRS(%r5)
/* Return 0. */
slr %r2,%r2
/* Return. */
br %r14
END(__getcontext)

View File

@ -62,8 +62,7 @@ ENTRY(__setcontext)
/* Load general purpose registers. */
lm %r0,%r15,SC_GPRS(%r5)
/* Return 1. */
la %r2,1
/* Return. */
br %r14
END(__setcontext)

View File

@ -25,9 +25,7 @@
/* __getcontext (const ucontext_t *ucp)
Saves the machine context in UCP such that when it is activated,
it appears as if __getcontext() returned again. The only difference
is that on a first return, %r2 contains 1 and on a subsequent
return, it contains 0.
it appears as if __getcontext() returned again.
This implementation is intended to be used for *synchronous* context
switches only. Therefore, it does not have to save anything
@ -61,11 +59,13 @@ ENTRY(__getcontext)
std %f14,SC_FPRS+112(%r5)
std %f15,SC_FPRS+120(%r5)
/* Set __getcontext return value to 0. */
slr %r2,%r2
/* Store general purpose registers. */
stmg %r0,%r15,SC_GPRS(%r5)
/* Return 0. */
slgr %r2,%r2
/* Return. */
br %r14
END(__getcontext)

View File

@ -62,8 +62,7 @@ ENTRY(__setcontext)
/* Load general purpose registers. */
lmg %r0,%r15,SC_GPRS(%r5)
/* Return 1. */
la %r2,1
/* Return. */
br %r14
END(__setcontext)

View File

@ -25,8 +25,14 @@ extern int __setcontext (__const ucontext_t *__ucp) __THROW;
int
__swapcontext (ucontext_t *oucp, const ucontext_t *ucp)
{
if (__getcontext (oucp) == 0)
__setcontext (ucp);
/* Save the current machine context to oucp. */
__getcontext (oucp);
/* Modify oucp to skip the __setcontext call on reactivation. */
oucp->uc_mcontext.gregs[14] = &&fake_return;
/* Restore the machine context in ucp. */
__setcontext (ucp);
fake_return:
return 0;
}