1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-12-24 17:51:17 +03:00

(charmap_read): Prepend the condition filename == NULL.

This commit is contained in:
Ulrich Drepper
2000-07-04 00:22:32 +00:00
parent 68eefde7b6
commit 4ad1d0cfbf
9 changed files with 150 additions and 53 deletions

View File

@@ -24,12 +24,20 @@
#include "spinlock.h"
#include "restart.h"
/* The status field of a spinlock has the following meaning:
0: spinlock is free
1: spinlock is taken, no thread is waiting on it
ADDR: psinlock is taken, ADDR is address of thread descriptor for
first waiting thread, other waiting threads are linked via
their p_nextlock field.
/* The status field of a spinlock is a pointer whose least significant
bit is a locked flag.
Thus the field values have the following meanings:
status == 0: spinlock is free
status == 1: spinlock is taken; no thread is waiting on it
(status & 1) == 1: spinlock is taken and (status & ~1L) is a
pointer to the first waiting thread; other
waiting threads are linked via the p_nextlock
field.
(status & 1) == 0: same as above, but spinlock is not taken.
The waiting list is not sorted by priority order.
Actually, we always insert at top of list (sole insertion mode
that can be performed without locking).
@@ -38,29 +46,70 @@
This is safe because there are no concurrent __pthread_unlock
operations -- only the thread that locked the mutex can unlock it. */
void internal_function __pthread_lock(struct _pthread_fastlock * lock,
pthread_descr self)
{
#if defined HAS_COMPARE_AND_SWAP
long oldstatus, newstatus;
int spurious_wakeup_count = 0;
int successful_seizure, spurious_wakeup_count = 0;
int spin_count = 0;
#endif
#if defined TEST_FOR_COMPARE_AND_SWAP
if (!__pthread_has_cas)
#endif
#if !defined HAS_COMPARE_AND_SWAP
{
__pthread_acquire(&lock->__spinlock);
return 0;
}
#endif
#if defined HAS_COMPARE_AND_SWAP
again:
/* On SMP, try spinning to get the lock. */
if (__pthread_smp_kernel) {
int max_count = lock->__spinlock * 2 + 10;
for (spin_count = 0; spin_count < max_count; spin_count++) {
if (((oldstatus = lock->__status) & 1) == 0) {
if(__compare_and_swap(&lock->__status, oldstatus, oldstatus | 1))
{
if (spin_count)
lock->__spinlock += (spin_count - lock->__spinlock) / 8;
return;
}
}
}
lock->__spinlock += (spin_count - lock->__spinlock) / 8;
}
/* No luck, try once more or suspend. */
do {
oldstatus = lock->__status;
if (oldstatus == 0) {
newstatus = 1;
successful_seizure = 0;
if ((oldstatus & 1) == 0) {
newstatus = oldstatus | 1;
successful_seizure = 1;
} else {
if (self == NULL)
self = thread_self();
newstatus = (long) self;
newstatus = (long) self | 1;
}
if (self != NULL) {
THREAD_SETMEM(self, p_nextlock, (pthread_descr) oldstatus);
THREAD_SETMEM(self, p_nextlock, (pthread_descr) (oldstatus & ~1L));
/* Make sure the store in p_nextlock completes before performing
the compare-and-swap */
MEMORY_BARRIER();
}
} while(! compare_and_swap(&lock->__status, oldstatus, newstatus,
&lock->__spinlock));
} while(! __compare_and_swap(&lock->__status, oldstatus, newstatus));
/* Suspend with guard against spurious wakeup.
This can happen in pthread_cond_timedwait_relative, when the thread
@@ -68,7 +117,7 @@ void internal_function __pthread_lock(struct _pthread_fastlock * lock,
locks the queue to remove itself. At that point it may still be on the
queue, and may be resumed by a condition signal. */
if (oldstatus != 0) {
if (!successful_seizure) {
for (;;) {
suspend(self);
if (self->p_nextlock != NULL) {
@@ -78,37 +127,50 @@ void internal_function __pthread_lock(struct _pthread_fastlock * lock,
}
break;
}
goto again;
}
/* Put back any resumes we caught that don't belong to us. */
while (spurious_wakeup_count--)
restart(self);
#endif
}
int __pthread_unlock(struct _pthread_fastlock * lock)
{
#if defined HAS_COMPARE_AND_SWAP
long oldstatus;
pthread_descr thr, * ptr, * maxptr;
int maxprio;
#endif
again:
oldstatus = lock->__status;
if (oldstatus == 0 || oldstatus == 1) {
/* No threads are waiting for this lock. Please note that we also
enter this case if the lock is not taken at all. If this wouldn't
be done here we would crash further down. */
if (! compare_and_swap_with_release_semantics (&lock->__status,
oldstatus, 0,
&lock->__spinlock))
goto again;
#if defined TEST_FOR_COMPARE_AND_SWAP
if (!__pthread_has_cas)
#endif
#if !defined HAS_COMPARE_AND_SWAP
{
lock->__spinlock = 0;
WRITE_MEMORY_BARRIER();
return 0;
}
#endif
#if defined HAS_COMPARE_AND_SWAP
again:
oldstatus = lock->__status;
while ((oldstatus = lock->__status) == 1) {
if (__compare_and_swap_with_release_semantics(&lock->__status,
oldstatus, 0))
return 0;
}
/* Find thread in waiting queue with maximal priority */
ptr = (pthread_descr *) &lock->__status;
thr = (pthread_descr) oldstatus;
thr = (pthread_descr) (oldstatus & ~1L);
maxprio = 0;
maxptr = ptr;
while (thr != (pthread_descr) 1) {
while (thr != 0) {
if (thr->p_priority >= maxprio) {
maxptr = ptr;
maxprio = thr->p_priority;
@@ -128,16 +190,25 @@ again:
/* Remove max prio thread from waiting list. */
if (maxptr == (pthread_descr *) &lock->__status) {
/* If max prio thread is at head, remove it with compare-and-swap
to guard against concurrent lock operation */
thr = (pthread_descr) oldstatus;
if (! compare_and_swap_with_release_semantics
(&lock->__status, oldstatus, (long)(thr->p_nextlock),
&lock->__spinlock))
to guard against concurrent lock operation. This removal
also has the side effect of marking the lock as released
because the new status comes from thr->p_nextlock whose
least significant bit is clear. */
thr = (pthread_descr) (oldstatus & ~1L);
if (! __compare_and_swap_with_release_semantics
(&lock->__status, oldstatus, (long)(thr->p_nextlock)))
goto again;
} else {
/* No risk of concurrent access, remove max prio thread normally */
/* No risk of concurrent access, remove max prio thread normally.
But in this case we must also flip the least significant bit
of the status to mark the lock as released. */
thr = *maxptr;
*maxptr = thr->p_nextlock;
do {
oldstatus = lock->__status;
} while (!__compare_and_swap_with_release_semantics(&lock->__status,
oldstatus, oldstatus & ~1L));
}
/* Prevent reordering of store to *maxptr above and store to thr->p_nextlock
below */
@@ -147,6 +218,7 @@ again:
restart(thr);
return 0;
#endif
}
/*