mirror of git://sourceware.org/git/glibc.git
Upadte.
2000-04-11 Ulrich Drepper <drepper@redhat.com> * internals.h: Define MEMORY_BARRIER as empty if not defined already. * spinlock.c (__pthread_lock): Add memory barriers. (__pthread_unlock): Likewise. * sysdeps/alpha/pt-machine.h (MEMORY_BARRIER): Define using mb instruction. (RELEASE): Not needed anymore. (__compare_and_swap): Mark asm as modifying memory. * sysdeps/powerpc/pt-machine.h (sync): Remove. Replace with definition of MEMORY_BARRIER. (__compare_and_swap): Use MEMORY_BARRIER instead of sync. * sysdeps/sparc/sparc32/pt-machine.h (RELEASE): Not needed anymore. (MEMORY_BARRIER): Define using stbar. * sysdeps/sparc/sparc64/pt-machine.h (MEMORY_BARRIER): Define using stbar. (__compare_and_swap): Use MEMORY_BARRIER to ensure ordering. Patch by Xavier Leroy <Xavier.Leroy@inria.fr> based on comments by Mike Burrows <m3b@pa.dec.com>.
This commit is contained in:
parent
e7c036b39e
commit
de26253715
|
@ -1,3 +1,23 @@
|
|||
2000-04-11 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* internals.h: Define MEMORY_BARRIER as empty if not defined already.
|
||||
* spinlock.c (__pthread_lock): Add memory barriers.
|
||||
(__pthread_unlock): Likewise.
|
||||
* sysdeps/alpha/pt-machine.h (MEMORY_BARRIER): Define using mb
|
||||
instruction.
|
||||
(RELEASE): Not needed anymore.
|
||||
(__compare_and_swap): Mark asm as modifying memory.
|
||||
* sysdeps/powerpc/pt-machine.h (sync): Remove. Replace with definition
|
||||
of MEMORY_BARRIER.
|
||||
(__compare_and_swap): Use MEMORY_BARRIER instead of sync.
|
||||
* sysdeps/sparc/sparc32/pt-machine.h (RELEASE): Not needed anymore.
|
||||
(MEMORY_BARRIER): Define using stbar.
|
||||
* sysdeps/sparc/sparc64/pt-machine.h (MEMORY_BARRIER): Define using
|
||||
stbar.
|
||||
(__compare_and_swap): Use MEMORY_BARRIER to ensure ordering.
|
||||
Patch by Xavier Leroy <Xavier.Leroy@inria.fr> based on comments by
|
||||
Mike Burrows <m3b@pa.dec.com>.
|
||||
|
||||
2000-04-09 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* signals.c (sigaction): Fix return value for the case SIG is one
|
||||
|
|
|
@ -357,6 +357,13 @@ static inline pthread_descr thread_self (void)
|
|||
#endif
|
||||
}
|
||||
|
||||
/* If MEMORY_BARRIER isn't defined in pt-machine.h, assume the architecture
|
||||
doesn't need a memory barrier instruction (e.g. Intel x86) */
|
||||
|
||||
#ifndef MEMORY_BARRIER
|
||||
#define MEMORY_BARRIER()
|
||||
#endif
|
||||
|
||||
/* Max number of times we must spin on a spinlock calling sched_yield().
|
||||
After MAX_SPIN_COUNT iterations, we put the calling thread to sleep. */
|
||||
|
||||
|
|
|
@ -54,6 +54,9 @@ void internal_function __pthread_lock(struct _pthread_fastlock * lock,
|
|||
if (self != NULL) {
|
||||
ASSERT(self->p_nextlock == NULL);
|
||||
THREAD_SETMEM(self, p_nextlock, (pthread_descr) oldstatus);
|
||||
/* 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));
|
||||
|
@ -108,8 +111,17 @@ again:
|
|||
maxprio = thr->p_priority;
|
||||
}
|
||||
ptr = &(thr->p_nextlock);
|
||||
/* Prevent reordering of the load of lock->__status above and the
|
||||
load of *ptr below, as well as reordering of *ptr between
|
||||
several iterations of the while loop. Some processors (e.g.
|
||||
multiprocessor Alphas) could perform such reordering even though
|
||||
the loads are dependent. */
|
||||
MEMORY_BARRIER();
|
||||
thr = *ptr;
|
||||
}
|
||||
/* Prevent reordering of the load of lock->__status above and
|
||||
thr->p_nextlock below */
|
||||
MEMORY_BARRIER();
|
||||
/* 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
|
||||
|
@ -124,6 +136,9 @@ again:
|
|||
thr = *maxptr;
|
||||
*maxptr = thr->p_nextlock;
|
||||
}
|
||||
/* Prevent reordering of store to *maxptr above and store to thr->p_nextlock
|
||||
below */
|
||||
MEMORY_BARRIER();
|
||||
/* Wake up the selected waiting thread */
|
||||
thr->p_nextlock = NULL;
|
||||
restart(thr);
|
||||
|
@ -149,6 +164,8 @@ int __pthread_compare_and_swap(long * ptr, long oldval, long newval,
|
|||
} else {
|
||||
res = 0;
|
||||
}
|
||||
/* Prevent reordering of store to *ptr above and store to *spinlock below */
|
||||
MEMORY_BARRIER();
|
||||
*spinlock = 0;
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,10 @@
|
|||
register char *stack_pointer __asm__("$30");
|
||||
|
||||
|
||||
/* Memory barrier; default is to do nothing */
|
||||
#define MEMORY_BARRIER() __asm__ __volatile__("mb" : : : "memory")
|
||||
|
||||
|
||||
/* Spinlock implementation; required. */
|
||||
PT_EI long int
|
||||
testandset (int *spinlock)
|
||||
|
@ -55,11 +59,6 @@ testandset (int *spinlock)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Spinlock release; default is just set to zero. */
|
||||
#define RELEASE(spinlock) \
|
||||
__asm__ __volatile__("mb" : : : "memory"); \
|
||||
*spinlock = 0
|
||||
|
||||
|
||||
/* Begin allocating thread stacks at this address. Default is to allocate
|
||||
them just below the initial program stack. */
|
||||
|
@ -102,7 +101,8 @@ __compare_and_swap (long int *p, long int oldval, long int newval)
|
|||
"2:\tmb\n"
|
||||
"/* End compare & swap */"
|
||||
: "=&r"(ret), "=m"(*p)
|
||||
: "r"(oldval), "r"(newval), "m"(*p));
|
||||
: "r"(oldval), "r"(newval), "m"(*p)
|
||||
: "memory");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -27,12 +27,7 @@
|
|||
|
||||
/* For multiprocessor systems, we want to ensure all memory accesses
|
||||
are completed before we reset a lock. */
|
||||
#if 0
|
||||
/* on non multiprocessor systems, you can just: */
|
||||
#define sync() /* nothing */
|
||||
#else
|
||||
#define sync() __asm__ __volatile__ ("sync")
|
||||
#endif
|
||||
#define MEMORY_BARRIER() __asm__ __volatile__ ("sync" : : : "memory")
|
||||
|
||||
/* Get some notion of the current stack. Need not be exactly the top
|
||||
of the stack, just something somewhere in the current frame. */
|
||||
|
@ -64,6 +59,6 @@ __compare_and_swap (long int *p, long int oldval, long int newval)
|
|||
: "=&r"(ret)
|
||||
: "r"(p), "r"(newval), "r"(oldval)
|
||||
: "cr0", "memory");
|
||||
sync();
|
||||
MEMORY_BARRIER();
|
||||
return ret == 0;
|
||||
}
|
||||
|
|
|
@ -37,9 +37,8 @@ testandset (int *spinlock)
|
|||
}
|
||||
|
||||
|
||||
/* Spinlock release; default is just set to zero. */
|
||||
#define RELEASE(spinlock) \
|
||||
__asm__ __volatile__("stbar; stb %1,%0" : "=m"(*(spinlock)) : "r"(0));
|
||||
/* Memory barrier; default is to do nothing */
|
||||
#define MEMORY_BARRIER() __asm__ __volatile__("stbar" : : : "memory")
|
||||
|
||||
|
||||
/* Get some notion of the current stack. Need not be exactly the top
|
||||
|
|
|
@ -37,6 +37,12 @@ testandset (int *spinlock)
|
|||
}
|
||||
|
||||
|
||||
/* Memory barrier; default is to do nothing */
|
||||
/* FIXME: is stbar OK, or should we use the more general membar instruction?
|
||||
If so, which mode to pass to membar? */
|
||||
#define MEMORY_BARRIER() __asm__ __volatile__("stbar" : : : "memory")
|
||||
|
||||
|
||||
/* Get some notion of the current stack. Need not be exactly the top
|
||||
of the stack, just something somewhere in the current frame. */
|
||||
#define CURRENT_STACK_FRAME stack_pointer
|
||||
|
@ -66,7 +72,7 @@ __compare_and_swap (long int *p, long int oldval, long int newval)
|
|||
__asm__ __volatile__ ("casx [%4], %2, %0"
|
||||
: "=r"(readval), "=m"(*p)
|
||||
: "r"(oldval), "m"(*p), "r"(p), "0"(newval));
|
||||
|
||||
MEMORY_BARRIER();
|
||||
return readval == oldval;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue