mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-18 00:41:06 +00:00
Update.
* sysdeps/alpha/dl-machine.h (RTLD_START):Rewrite for new init function interface. Patch by Richard Henderson <rth@cygnus.com>.
This commit is contained in:
parent
a5a6f9262e
commit
ef187474bc
@ -1,5 +1,8 @@
|
||||
2000-04-15 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* sysdeps/alpha/dl-machine.h (RTLD_START):Rewrite for new init
|
||||
function interface. Patch by Richard Henderson <rth@cygnus.com>.
|
||||
|
||||
* posix/Makefile (headers): Add spawn.h.
|
||||
(distribute): Add spawn_int.h.
|
||||
(routines): Add spawn_faction_init, spawn_faction_destroy,
|
||||
|
@ -1,5 +1,21 @@
|
||||
2000-04-15 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* condvar.c: Remove all the special code to handle cond_timedwait.
|
||||
Use timedsuspend instead.
|
||||
* internals.h: Declare __pthread_timedsuspend_old,
|
||||
__pthread_timedsuspend_new, and __pthread_timedsuspend.
|
||||
Remove declaration of __pthread_init_condvar.
|
||||
* pthread.c: Define __pthread_timedsuspend variable.
|
||||
(__pthread_timedsuspend_old): New function. Timed suspension
|
||||
implementation for old Linux kernels.
|
||||
(__pthread_timedsuspend_new): New function. Timed suspension
|
||||
implementation for new Linux kernels.
|
||||
* restart.h (timedsuspend): New function. Call appropriate
|
||||
suspension function through __pthread_timedsuspend.
|
||||
* semaphore.c (sem_timedwait): Use timedsuspend, don't duplicate
|
||||
the code.
|
||||
Patch by Kaz Kylheku <kaz@ashi.footprints.net>.
|
||||
|
||||
* internals.h (WRITE_MEMORY_BARRIER): Define as MEMORY_BARRIER if
|
||||
undefined.
|
||||
* spinlock.c: Use WRITE_MEMORY_BARRIER instead of MEMORY_BARRIER
|
||||
|
@ -25,22 +25,6 @@
|
||||
#include "queue.h"
|
||||
#include "restart.h"
|
||||
|
||||
static int pthread_cond_timedwait_relative_old(pthread_cond_t *,
|
||||
pthread_mutex_t *, const struct timespec *);
|
||||
|
||||
static int pthread_cond_timedwait_relative_new(pthread_cond_t *,
|
||||
pthread_mutex_t *, const struct timespec *);
|
||||
|
||||
static int (*pthread_cond_tw_rel)(pthread_cond_t *, pthread_mutex_t *,
|
||||
const struct timespec *) = pthread_cond_timedwait_relative_old;
|
||||
|
||||
/* initialize this module */
|
||||
void __pthread_init_condvar(int rt_sig_available)
|
||||
{
|
||||
if (rt_sig_available)
|
||||
pthread_cond_tw_rel = pthread_cond_timedwait_relative_new;
|
||||
}
|
||||
|
||||
int pthread_cond_init(pthread_cond_t *cond,
|
||||
const pthread_condattr_t *cond_attr)
|
||||
{
|
||||
@ -127,151 +111,13 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The following function is used on kernels that don't have rt signals.
|
||||
SIGUSR1 is used as the restart signal. The different code is needed
|
||||
because that ordinary signal does not queue. */
|
||||
|
||||
static int
|
||||
pthread_cond_timedwait_relative_old(pthread_cond_t *cond,
|
||||
pthread_cond_timedwait_relative(pthread_cond_t *cond,
|
||||
pthread_mutex_t *mutex,
|
||||
const struct timespec * abstime)
|
||||
{
|
||||
volatile pthread_descr self = thread_self();
|
||||
sigset_t unblock, initial_mask;
|
||||
int already_canceled = 0;
|
||||
int was_signalled = 0;
|
||||
sigjmp_buf jmpbuf;
|
||||
pthread_extricate_if extr;
|
||||
|
||||
/* Check whether the mutex is locked and owned by this thread. */
|
||||
if (mutex->__m_kind != PTHREAD_MUTEX_FAST_NP && mutex->__m_owner != self)
|
||||
return EINVAL;
|
||||
|
||||
/* Set up extrication interface */
|
||||
extr.pu_object = cond;
|
||||
extr.pu_extricate_func = cond_extricate_func;
|
||||
|
||||
/* Register extrication interface */
|
||||
__pthread_set_own_extricate_if(self, &extr);
|
||||
|
||||
/* Enqueue to wait on the condition and check for cancellation. */
|
||||
__pthread_lock(&cond->__c_lock, self);
|
||||
if (!(THREAD_GETMEM(self, p_canceled)
|
||||
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
|
||||
enqueue(&cond->__c_waiting, self);
|
||||
else
|
||||
already_canceled = 1;
|
||||
__pthread_spin_unlock(&cond->__c_lock);
|
||||
|
||||
if (already_canceled) {
|
||||
__pthread_set_own_extricate_if(self, 0);
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(mutex);
|
||||
|
||||
if (atomic_decrement(&self->p_resume_count) == 0) {
|
||||
/* Set up a longjmp handler for the restart signal, unblock
|
||||
the signal and sleep. */
|
||||
|
||||
if (sigsetjmp(jmpbuf, 1) == 0) {
|
||||
THREAD_SETMEM(self, p_signal_jmp, &jmpbuf);
|
||||
THREAD_SETMEM(self, p_signal, 0);
|
||||
/* Unblock the restart signal */
|
||||
sigemptyset(&unblock);
|
||||
sigaddset(&unblock, __pthread_sig_restart);
|
||||
sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);
|
||||
|
||||
while (1) {
|
||||
struct timeval now;
|
||||
struct timespec reltime;
|
||||
|
||||
/* Compute a time offset relative to now. */
|
||||
__gettimeofday (&now, NULL);
|
||||
reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
|
||||
reltime.tv_sec = abstime->tv_sec - now.tv_sec;
|
||||
if (reltime.tv_nsec < 0) {
|
||||
reltime.tv_nsec += 1000000000;
|
||||
reltime.tv_sec -= 1;
|
||||
}
|
||||
|
||||
/* Sleep for the required duration. If woken by a signal,
|
||||
resume waiting as required by Single Unix Specification. */
|
||||
if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Block the restart signal again */
|
||||
sigprocmask(SIG_SETMASK, &initial_mask, NULL);
|
||||
was_signalled = 0;
|
||||
} else {
|
||||
was_signalled = 1;
|
||||
}
|
||||
THREAD_SETMEM(self, p_signal_jmp, NULL);
|
||||
}
|
||||
|
||||
/* Now was_signalled is true if we exited the above code
|
||||
due to the delivery of a restart signal. In that case,
|
||||
we know we have been dequeued and resumed and that the
|
||||
resume count is balanced. Otherwise, there are some
|
||||
cases to consider. First, try to bump up the resume count
|
||||
back to zero. If it goes to 1, it means restart() was
|
||||
invoked on this thread. The signal must be consumed
|
||||
and the count bumped down and everything is cool.
|
||||
Otherwise, no restart was delivered yet, so we remove
|
||||
the thread from the queue. If this succeeds, it's a clear
|
||||
case of timeout. If we fail to remove from the queue, then we
|
||||
must wait for a restart. */
|
||||
|
||||
if (!was_signalled) {
|
||||
if (atomic_increment(&self->p_resume_count) != -1) {
|
||||
__pthread_wait_for_restart_signal(self);
|
||||
atomic_decrement(&self->p_resume_count); /* should be zero now! */
|
||||
} else {
|
||||
int was_on_queue;
|
||||
__pthread_lock(&cond->__c_lock, self);
|
||||
was_on_queue = remove_from_queue(&cond->__c_waiting, self);
|
||||
__pthread_spin_unlock(&cond->__c_lock);
|
||||
|
||||
if (was_on_queue) {
|
||||
__pthread_set_own_extricate_if(self, 0);
|
||||
pthread_mutex_lock(mutex);
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
|
||||
suspend(self);
|
||||
}
|
||||
}
|
||||
|
||||
__pthread_set_own_extricate_if(self, 0);
|
||||
|
||||
/* The remaining logic is the same as in other cancellable waits,
|
||||
such as pthread_join sem_wait or pthread_cond wait. */
|
||||
|
||||
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_mutex_lock(mutex);
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The following function is used on new (late 2.1 and 2.2 and higher) kernels
|
||||
that have rt signals which queue. */
|
||||
|
||||
static int
|
||||
pthread_cond_timedwait_relative_new(pthread_cond_t *cond,
|
||||
pthread_mutex_t *mutex,
|
||||
const struct timespec * abstime)
|
||||
{
|
||||
volatile pthread_descr self = thread_self();
|
||||
sigset_t unblock, initial_mask;
|
||||
int already_canceled = 0;
|
||||
int was_signalled = 0;
|
||||
sigjmp_buf jmpbuf;
|
||||
pthread_extricate_if extr;
|
||||
|
||||
/* Check whether the mutex is locked and owned by this thread. */
|
||||
@ -279,7 +125,6 @@ pthread_cond_timedwait_relative_new(pthread_cond_t *cond,
|
||||
return EINVAL;
|
||||
|
||||
already_canceled = 0;
|
||||
was_signalled = 0;
|
||||
|
||||
/* Set up extrication interface */
|
||||
extr.pu_object = cond;
|
||||
@ -304,56 +149,7 @@ pthread_cond_timedwait_relative_new(pthread_cond_t *cond,
|
||||
|
||||
pthread_mutex_unlock(mutex);
|
||||
|
||||
/* Set up a longjmp handler for the restart signal, unblock
|
||||
the signal and sleep. */
|
||||
|
||||
if (sigsetjmp(jmpbuf, 1) == 0) {
|
||||
THREAD_SETMEM(self, p_signal_jmp, &jmpbuf);
|
||||
THREAD_SETMEM(self, p_signal, 0);
|
||||
/* Unblock the restart signal */
|
||||
sigemptyset(&unblock);
|
||||
sigaddset(&unblock, __pthread_sig_restart);
|
||||
sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);
|
||||
|
||||
while (1) {
|
||||
struct timeval now;
|
||||
struct timespec reltime;
|
||||
|
||||
/* Compute a time offset relative to now. */
|
||||
__gettimeofday (&now, NULL);
|
||||
reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
|
||||
reltime.tv_sec = abstime->tv_sec - now.tv_sec;
|
||||
if (reltime.tv_nsec < 0) {
|
||||
reltime.tv_nsec += 1000000000;
|
||||
reltime.tv_sec -= 1;
|
||||
}
|
||||
|
||||
/* Sleep for the required duration. If woken by a signal,
|
||||
resume waiting as required by Single Unix Specification. */
|
||||
if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Block the restart signal again */
|
||||
sigprocmask(SIG_SETMASK, &initial_mask, NULL);
|
||||
was_signalled = 0;
|
||||
} else {
|
||||
was_signalled = 1;
|
||||
}
|
||||
THREAD_SETMEM(self, p_signal_jmp, NULL);
|
||||
|
||||
/* Now was_signalled is true if we exited the above code
|
||||
due to the delivery of a restart signal. In that case,
|
||||
everything is cool. We have been removed from the queue
|
||||
by the other thread, and consumed its signal.
|
||||
|
||||
Otherwise we this thread woke up spontaneously, or due to a signal other
|
||||
than restart. The next thing to do is to try to remove the thread
|
||||
from the queue. This may fail due to a race against another thread
|
||||
trying to do the same. In the failed case, we know we were signalled,
|
||||
and we may also have to consume a restart signal. */
|
||||
|
||||
if (!was_signalled) {
|
||||
if (!timedsuspend(self, abstime) == 0) {
|
||||
int was_on_queue;
|
||||
|
||||
/* __pthread_lock will queue back any spurious restarts that
|
||||
@ -393,7 +189,7 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
const struct timespec * abstime)
|
||||
{
|
||||
/* Indirect call through pointer! */
|
||||
return pthread_cond_tw_rel(cond, mutex, abstime);
|
||||
return pthread_cond_timedwait_relative(cond, mutex, abstime);
|
||||
}
|
||||
|
||||
int pthread_cond_signal(pthread_cond_t *cond)
|
||||
|
@ -431,18 +431,19 @@ extern void __pthread_kill_other_threads_np (void);
|
||||
|
||||
void __pthread_restart_old(pthread_descr th);
|
||||
void __pthread_suspend_old(pthread_descr self);
|
||||
int __pthread_timedsuspend_old(pthread_descr self, const struct timespec *abs);
|
||||
|
||||
void __pthread_restart_new(pthread_descr th);
|
||||
void __pthread_suspend_new(pthread_descr self);
|
||||
int __pthread_timedsuspend_new(pthread_descr self, const struct timespec *abs);
|
||||
|
||||
void __pthread_wait_for_restart_signal(pthread_descr self);
|
||||
|
||||
void __pthread_init_condvar(int rt_sig_available);
|
||||
|
||||
/* Global pointers to old or new suspend functions */
|
||||
|
||||
extern void (*__pthread_restart)(pthread_descr);
|
||||
extern void (*__pthread_suspend)(pthread_descr);
|
||||
extern int (*__pthread_timedsuspend)(pthread_descr, const struct timespec *);
|
||||
|
||||
/* Prototypes for the function without cancelation support when the
|
||||
normal version has it. */
|
||||
|
@ -166,6 +166,7 @@ int __pthread_exit_code = 0;
|
||||
|
||||
void (*__pthread_restart)(pthread_descr) = __pthread_restart_old;
|
||||
void (*__pthread_suspend)(pthread_descr) = __pthread_suspend_old;
|
||||
int (*__pthread_timedsuspend)(pthread_descr, const struct timespec *) = __pthread_timedsuspend_old;
|
||||
|
||||
/* Communicate relevant LinuxThreads constants to gdb */
|
||||
|
||||
@ -238,7 +239,6 @@ init_rtsigs (void)
|
||||
__pthread_sig_cancel = SIGUSR2;
|
||||
__pthread_sig_debug = 0;
|
||||
#endif
|
||||
__pthread_init_condvar(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -246,10 +246,9 @@ init_rtsigs (void)
|
||||
current_rtmin = __SIGRTMIN + 3;
|
||||
__pthread_restart = __pthread_restart_new;
|
||||
__pthread_suspend = __pthread_wait_for_restart_signal;
|
||||
__pthread_init_condvar(1);
|
||||
__pthread_timedsuspend = __pthread_timedsuspend_new;
|
||||
#else
|
||||
current_rtmin = __SIGRTMIN;
|
||||
__pthread_init_condvar(0);
|
||||
#endif
|
||||
|
||||
current_rtmax = __SIGRTMAX;
|
||||
@ -826,7 +825,8 @@ void __pthread_wait_for_restart_signal(pthread_descr self)
|
||||
} while (self->p_signal !=__pthread_sig_restart );
|
||||
}
|
||||
|
||||
/* The _old variants are for 2.0 and early 2.1 kernels which don't have RT signals.
|
||||
/* The _old variants are for 2.0 and early 2.1 kernels which don't have RT
|
||||
signals.
|
||||
On these kernels, we use SIGUSR1 and SIGUSR2 for restart and cancellation.
|
||||
Since the restart signal does not queue, we use an atomic counter to create
|
||||
queuing semantics. This is needed to resolve a rare race condition in
|
||||
@ -844,6 +844,83 @@ void __pthread_suspend_old(pthread_descr self)
|
||||
__pthread_wait_for_restart_signal(self);
|
||||
}
|
||||
|
||||
int
|
||||
__pthread_timedsuspend_old(pthread_descr self, const struct timespec *abstime)
|
||||
{
|
||||
sigset_t unblock, initial_mask;
|
||||
int was_signalled = 0;
|
||||
sigjmp_buf jmpbuf;
|
||||
|
||||
if (atomic_decrement(&self->p_resume_count) == 0) {
|
||||
/* Set up a longjmp handler for the restart signal, unblock
|
||||
the signal and sleep. */
|
||||
|
||||
if (sigsetjmp(jmpbuf, 1) == 0) {
|
||||
THREAD_SETMEM(self, p_signal_jmp, &jmpbuf);
|
||||
THREAD_SETMEM(self, p_signal, 0);
|
||||
/* Unblock the restart signal */
|
||||
sigemptyset(&unblock);
|
||||
sigaddset(&unblock, __pthread_sig_restart);
|
||||
sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);
|
||||
|
||||
while (1) {
|
||||
struct timeval now;
|
||||
struct timespec reltime;
|
||||
|
||||
/* Compute a time offset relative to now. */
|
||||
__gettimeofday (&now, NULL);
|
||||
reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
|
||||
reltime.tv_sec = abstime->tv_sec - now.tv_sec;
|
||||
if (reltime.tv_nsec < 0) {
|
||||
reltime.tv_nsec += 1000000000;
|
||||
reltime.tv_sec -= 1;
|
||||
}
|
||||
|
||||
/* Sleep for the required duration. If woken by a signal,
|
||||
resume waiting as required by Single Unix Specification. */
|
||||
if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Block the restart signal again */
|
||||
sigprocmask(SIG_SETMASK, &initial_mask, NULL);
|
||||
was_signalled = 0;
|
||||
} else {
|
||||
was_signalled = 1;
|
||||
}
|
||||
THREAD_SETMEM(self, p_signal_jmp, NULL);
|
||||
}
|
||||
|
||||
/* Now was_signalled is true if we exited the above code
|
||||
due to the delivery of a restart signal. In that case,
|
||||
we know we have been dequeued and resumed and that the
|
||||
resume count is balanced. Otherwise, there are some
|
||||
cases to consider. First, try to bump up the resume count
|
||||
back to zero. If it goes to 1, it means restart() was
|
||||
invoked on this thread. The signal must be consumed
|
||||
and the count bumped down and everything is cool. We
|
||||
can return a 1 to the caller.
|
||||
Otherwise, no restart was delivered yet, so a potential
|
||||
race exists; we return a 0 to the caller which must deal
|
||||
with this race in an appropriate way; for example by
|
||||
atomically removing the thread from consideration for a
|
||||
wakeup---if such a thing fails, it means a restart is
|
||||
being delivered. */
|
||||
|
||||
if (!was_signalled) {
|
||||
if (atomic_increment(&self->p_resume_count) != -1) {
|
||||
__pthread_wait_for_restart_signal(self);
|
||||
atomic_decrement(&self->p_resume_count); /* should be zero now! */
|
||||
/* woke spontaneously and consumed restart signal */
|
||||
return 1;
|
||||
}
|
||||
/* woke spontaneously but did not consume restart---caller must resolve */
|
||||
return 0;
|
||||
}
|
||||
/* woken due to restart signal */
|
||||
return 1;
|
||||
}
|
||||
|
||||
void __pthread_restart_new(pthread_descr th)
|
||||
{
|
||||
kill(th->p_pid, __pthread_sig_restart);
|
||||
@ -852,6 +929,62 @@ void __pthread_restart_new(pthread_descr th)
|
||||
/* There is no __pthread_suspend_new because it would just
|
||||
be a wasteful wrapper for __pthread_wait_for_restart_signal */
|
||||
|
||||
int
|
||||
__pthread_timedsuspend_new(pthread_descr self, const struct timespec *abstime)
|
||||
{
|
||||
sigset_t unblock, initial_mask;
|
||||
int was_signalled = 0;
|
||||
sigjmp_buf jmpbuf;
|
||||
|
||||
if (sigsetjmp(jmpbuf, 1) == 0) {
|
||||
THREAD_SETMEM(self, p_signal_jmp, &jmpbuf);
|
||||
THREAD_SETMEM(self, p_signal, 0);
|
||||
/* Unblock the restart signal */
|
||||
sigemptyset(&unblock);
|
||||
sigaddset(&unblock, __pthread_sig_restart);
|
||||
sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);
|
||||
|
||||
while (1) {
|
||||
struct timeval now;
|
||||
struct timespec reltime;
|
||||
|
||||
/* Compute a time offset relative to now. */
|
||||
__gettimeofday (&now, NULL);
|
||||
reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
|
||||
reltime.tv_sec = abstime->tv_sec - now.tv_sec;
|
||||
if (reltime.tv_nsec < 0) {
|
||||
reltime.tv_nsec += 1000000000;
|
||||
reltime.tv_sec -= 1;
|
||||
}
|
||||
|
||||
/* Sleep for the required duration. If woken by a signal,
|
||||
resume waiting as required by Single Unix Specification. */
|
||||
if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Block the restart signal again */
|
||||
sigprocmask(SIG_SETMASK, &initial_mask, NULL);
|
||||
was_signalled = 0;
|
||||
} else {
|
||||
was_signalled = 1;
|
||||
}
|
||||
THREAD_SETMEM(self, p_signal_jmp, NULL);
|
||||
|
||||
/* Now was_signalled is true if we exited the above code
|
||||
due to the delivery of a restart signal. In that case,
|
||||
everything is cool. We have been removed from whatever
|
||||
we were waiting on by the other thread, and consumed its signal.
|
||||
|
||||
Otherwise we this thread woke up spontaneously, or due to a signal other
|
||||
than restart. This is an ambiguous case that must be resolved by
|
||||
the caller; the thread is still eligible for a restart wakeup
|
||||
so there is a race. */
|
||||
|
||||
return was_signalled;
|
||||
}
|
||||
|
||||
|
||||
/* Debugging aid */
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -25,3 +25,9 @@ static inline void suspend(pthread_descr self)
|
||||
{
|
||||
__pthread_suspend(self); /* see pthread.c */
|
||||
}
|
||||
|
||||
static inline int timedsuspend(pthread_descr self,
|
||||
const struct timespec *abstime)
|
||||
{
|
||||
return __pthread_timedsuspend(self, abstime); /* see pthread.c */
|
||||
}
|
||||
|
@ -195,10 +195,6 @@ int sem_timedwait(sem_t *sem, const struct timespec *abstime)
|
||||
pthread_descr self = thread_self();
|
||||
pthread_extricate_if extr;
|
||||
int already_canceled = 0;
|
||||
int was_signalled = 0;
|
||||
sigjmp_buf jmpbuf;
|
||||
sigset_t unblock;
|
||||
sigset_t initial_mask;
|
||||
|
||||
__pthread_lock((pthread_spinlock_t *) &sem->__sem_lock, self);
|
||||
if (sem->__sem_value > 0) {
|
||||
@ -233,56 +229,7 @@ int sem_timedwait(sem_t *sem, const struct timespec *abstime)
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
|
||||
/* Set up a longjmp handler for the restart signal, unblock
|
||||
the signal and sleep. */
|
||||
|
||||
if (sigsetjmp(jmpbuf, 1) == 0) {
|
||||
THREAD_SETMEM(self, p_signal_jmp, &jmpbuf);
|
||||
THREAD_SETMEM(self, p_signal, 0);
|
||||
/* Unblock the restart signal */
|
||||
sigemptyset(&unblock);
|
||||
sigaddset(&unblock, __pthread_sig_restart);
|
||||
sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);
|
||||
|
||||
while (1) {
|
||||
struct timeval now;
|
||||
struct timespec reltime;
|
||||
|
||||
/* Compute a time offset relative to now. */
|
||||
__gettimeofday (&now, NULL);
|
||||
reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
|
||||
reltime.tv_sec = abstime->tv_sec - now.tv_sec;
|
||||
if (reltime.tv_nsec < 0) {
|
||||
reltime.tv_nsec += 1000000000;
|
||||
reltime.tv_sec -= 1;
|
||||
}
|
||||
|
||||
/* Sleep for the required duration. If woken by a signal,
|
||||
resume waiting as required by Single Unix Specification. */
|
||||
if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Block the restart signal again */
|
||||
sigprocmask(SIG_SETMASK, &initial_mask, NULL);
|
||||
was_signalled = 0;
|
||||
} else {
|
||||
was_signalled = 1;
|
||||
}
|
||||
THREAD_SETMEM(self, p_signal_jmp, NULL);
|
||||
|
||||
/* Now was_signalled is true if we exited the above code
|
||||
due to the delivery of a restart signal. In that case,
|
||||
everything is cool. We have been removed from the queue
|
||||
by the other thread, and consumed its signal.
|
||||
|
||||
Otherwise we this thread woke up spontaneously, or due to a signal other
|
||||
than restart. The next thing to do is to try to remove the thread
|
||||
from the queue. This may fail due to a race against another thread
|
||||
trying to do the same. In the failed case, we know we were signalled,
|
||||
and we may also have to consume a restart signal. */
|
||||
|
||||
if (!was_signalled) {
|
||||
if (timedsuspend(self, abstime) == 0) {
|
||||
int was_on_queue;
|
||||
|
||||
/* __pthread_lock will queue back any spurious restarts that
|
||||
|
@ -289,37 +289,64 @@ _dl_start_user:
|
||||
/* Store the highest stack address. */
|
||||
stq $30, __libc_stack_end
|
||||
/* See if we were run as a command with the executable file
|
||||
name as an extra leading argument. If so, adjust the stack
|
||||
pointer to skip _dl_skip_args words. */
|
||||
name as an extra leading argument. */
|
||||
ldl $1, _dl_skip_args
|
||||
beq $1, 0f
|
||||
ldq $2, 0($sp)
|
||||
subq $2, $1, $2
|
||||
s8addq $1, $sp, $sp
|
||||
stq $2, 0($sp)
|
||||
/* Load _dl_main_searchlist into s1 to pass to _dl_init_next. */
|
||||
0: ldq $10, _dl_main_searchlist
|
||||
/* Call _dl_init_next to return the address of an initializer
|
||||
function to run. */
|
||||
1: mov $10, $16
|
||||
jsr $26, _dl_init_next
|
||||
ldgp $gp, 0($26)
|
||||
beq $0, 2f
|
||||
mov $0, $27
|
||||
jsr $26, ($0)
|
||||
ldgp $gp, 0($26)
|
||||
br 1b
|
||||
2: /* Clear the startup flag. */
|
||||
stl $31, _dl_starting_up
|
||||
beq $1, $fixup_stack
|
||||
$fixup_stack_ret:
|
||||
/* The special initializer gets called with the stack just
|
||||
as the application's entry point will see it; it can
|
||||
switch stacks if it moves these contents over. */
|
||||
" RTLD_START_SPECIAL_INIT "
|
||||
/* Call _dl_init(_dl_loaded, argc, argv, envp) to run initializers. */
|
||||
ldq $16, _dl_loaded
|
||||
ldq $17, 0($sp)
|
||||
lda $18, 8($sp)
|
||||
s8addq $17, 8, $19
|
||||
addq $19, $18, $19
|
||||
jsr $26, _dl_init
|
||||
/* Pass our finalizer function to the user in $0. */
|
||||
lda $0, _dl_fini
|
||||
/* Jump to the user's entry point. */
|
||||
mov $9, $27
|
||||
jmp ($9)
|
||||
$fixup_stack:
|
||||
/* Adjust the stack pointer to skip _dl_skip_args words. This
|
||||
involves copying everything down, since the stack pointer must
|
||||
always be 16-byte aligned. */
|
||||
ldq $2, 0($sp)
|
||||
subq $2, $1, $2
|
||||
mov $sp, $4
|
||||
s8addq $2, $sp, $3
|
||||
stq $2, 0($sp)
|
||||
/* Copy down argv. */
|
||||
0: ldq $5, 8($3)
|
||||
addq $4, 8, $4
|
||||
addq $3, 8, $3
|
||||
stq $5, 0($4)
|
||||
bne $5, 0b
|
||||
/* Copy down envp. */
|
||||
1: ldq $5, 8($3)
|
||||
addq $4, 8, $4
|
||||
addq $3, 8, $3
|
||||
stq $5, 0($4)
|
||||
bne $5, 1b
|
||||
/* Copy down auxiliary table. */
|
||||
2: ldq $5, 8($3)
|
||||
ldq $6, 16($3)
|
||||
addq $4, 16, $4
|
||||
addq $3, 16, $3
|
||||
stq $5, -8($4)
|
||||
stq $6, 0($4)
|
||||
bne $5, 2b
|
||||
br $fixup_stack_ret
|
||||
.end _dl_start_user
|
||||
.set noat
|
||||
.previous");
|
||||
|
||||
#ifndef RTLD_START_SPECIAL_INIT
|
||||
#define RTLD_START_SPECIAL_INIT /* nothing */
|
||||
#endif
|
||||
|
||||
/* Nonzero iff TYPE describes relocation of a PLT entry, so
|
||||
PLT entries should not be allowed to define the value. */
|
||||
#define elf_machine_lookup_noplt_p(type) ((type) == R_ALPHA_JMP_SLOT)
|
||||
@ -350,7 +377,7 @@ elf_machine_fixup_plt(struct link_map *l, const Elf64_Rela *reloc,
|
||||
/* Recover the PLT entry address by calculating reloc's index into the
|
||||
.rela.plt, and finding that entry in the .plt. */
|
||||
rela_plt = (void *) D_PTR (l, l_info[DT_JMPREL]);
|
||||
plte = (void *) (D_PTR (l, [DT_PLTGOT]) + 32);
|
||||
plte = (void *) (D_PTR (l, l_info[DT_PLTGOT]) + 32);
|
||||
plte += 3 * (reloc - rela_plt);
|
||||
|
||||
/* Find the displacement from the plt entry to the function. */
|
||||
|
@ -68,7 +68,7 @@ extern int ADJTIMEX (struct TIMEX *);
|
||||
#include <sysdeps/unix/sysv/linux/adjtime.c>
|
||||
|
||||
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
|
||||
compat_symbol (libc, __adjtime_tv32, adjtime, GLIBC_2.0);
|
||||
compat_symbol (libc, __adjtime_tv32, adjtime, GLIBC_2_0);
|
||||
#endif
|
||||
|
||||
#undef TIMEVAL
|
||||
|
Loading…
Reference in New Issue
Block a user