mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-22 10:50:07 +00:00
Update.
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:
parent
bf9d1166a0
commit
58f46c794a
11
ChangeLog
11
ChangeLog
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
#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)
|
||||
|
@ -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. */
|
||||
|
@ -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, ...);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,7 @@ int __old_sem_wait(old_sem_t * sem)
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
#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)))
|
||||
|
@ -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
153
linuxthreads/tst-cancel.c
Normal 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;
|
||||
}
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user