Implement linuxthreads on HPPA
PATCH 1/1 Implement linuxthreads on HPPA
libc-alpha,
I've reworked the hppa pthreads patch to be as low impact as possible :) Though some things need to be done, namely, hppa needs the lock variable to be 16-byte aligned. This alignment requirement means all sorts of ugly things, from wrappers to avoid non-constant named initializers, to the use of a struct for a lock variable.
Thanks for all your feedback.
My apologies for the slow return, school called :}
c.
Round 2 ...
linuxthreads/descr.h | 2 linuxthreads/pt-machine.c | 4 linuxthreads/pthread.c | 16 - linuxthreads/spinlock.c | 24 - linuxthreads/spinlock.h | 26 + linuxthreads/sysdeps/hppa/pspinlock.c | 24 - linuxthreads/sysdeps/hppa/pt-machine.h | 46 ++- linuxthreads/sysdeps/pthread/bits/libc-lock.h | 6 linuxthreads/sysdeps/pthread/bits/pthreadtypes.h | 8 linuxthreads/sysdeps/unix/sysv/linux/hppa/bits/initspin.h | 22 + linuxthreads/sysdeps/unix/sysv/linux/hppa/bits/pthreadtypes.h | 146 ++++++++++ linuxthreads/sysdeps/unix/sysv/linux/hppa/pt-initfini.c | 132 ++++----- sysdeps/hppa/dl-fptr.c | 10 13 files changed, 336 insertions(+), 130 deletions(-)
---
2002-11-11 Carlos O'Donell <[email protected]>
* linuxthreads/descr.h: Change spinlock type to __atomic_lock_t.
* linuxthreads/pt-machine.c: Change extern definition of testandset so it uses __atomic_lock_t instead of int.
* linuxthreads/pthread.c:
(__pthread_initialize_minimal): Replace the use of __LT_SPINLOCK_INIT with __LT_INITIALIZER_NOT_ZERO in cases where it is used to check wether the initialization should occur or not. (__pthread_initialize_manager): Likewise.
* linuxthreads/spinlock.h: Add default define for lock_held if it has not already been defined. Create the __pthread_lock_define_initialized macro to wrap up the use of an alternate initializer. Change __pthread_compare_and_swap to use __atomic_lock_t, (compare_and_swap): Change function definitions to use __atomic_lock_t (compare_and_swap_with_release_semantics): Likewise. (__pthread_compare_and_swap): Likewise.
* linuxthreads/spinlock.c: Change definition of __pthread_acquire to use __atomic_lock_t. Modify struct wait_node to use __atomic_lock_t as lock. Wrap definition and init of wait_node_free_list_spinlock in macro.
(__pthread_release): Change function definition to use __atomic_lock_t (__pthread_alt_lock): Change instances of abandoned = 0 to abandoned = __LT_SPINLOCK_INIT. (__pthread_alt_timedlock): Likewise. (__pthread_alt_unlock): Use lock_held instead of just checking abandoned == 0. Typo fix in comment from "canno6" to "cannot" (__pthread_compare_and_swap): Change function definition to use __atomic_lock_t.
(__pthread_acquire): Likewise.
* linuxthreads/sysdeps/hppa/pspinlock.c: Define __ldcw macro for PA's single atomic operation.
(__pthread_spin_lock): Modified to use __ldcw macro. (__pthread_spin_trylock): Likewise.
* linuxthreads/sysdeps/hppa/pt-machine.h: Add sys/types.h to pull in __atomic_long_t definition. Remove extern testandset define. Add defines for FLOATING_STACKS and ARACH_STACK_MAX_SIZE. Add lock_held macro.
(__get_cr27): New.
(__set_cr27): New.
(__load_and_clear): New.
(testandset): Modified to emulate testandset using __load_and_clear.
* linuxthreads/sysdeps/pthread/bits/libc-lock.h: Replace the use of __LT_SPINLOCK_INIT with that of __LT_INITIALIZER_NOT_ZERO.
* linuxthreads/sysdeps/pthread/bits/pthreadtypes.h:
Define default __atomic_lock_t to be an int. Change struct _pthread_fastlock to reflect name change.
* linuxthreads/sysdeps/unix/sysv/linux/hppa/bits/initspin.h:
Change macro's to reflect that lock is actually struct.
* linuxthreads/sysdeps/unix/sysv/linux/hppa/bits/pthreadtypes.h: New.
* linuxthreads/sysdeps/unix/sysv/linux/hppa/pt-initfini.c:
Avoid unterminated string literals.
* sysdeps/hppa/dl-fptr.c: Change global lock to use __LT_SPINLOCK_ALT_INIT.
(__hppa_make_fptr): Use __LT_SPINLOCK_INIT to clear locks. (_dl_unmap): Likewise.
(_dl_lookup_address): Likewise, and clear bottom two bits of address to fix function pointer calculation, see make_ftpr for the reasoning.
linuxthreads/descr.h +1 -1
@@ -61,7 +61,7 @@/* Atomic counter made possible by compare_and_swap */ struct pthread_atomic {long p_count; -int p_spinlock; +__atomic_lock_t p_spinlock; };
linuxthreads/pt-machine.c +3 -1
@@ -19,7 +19,9 @@#define PT_EI -extern long int testandset (int *spinlock); +#include <pthread.h> + +extern long int testandset (__atomic_lock_t *spinlock);extern int __compare_and_swap (long int *p,long int oldval,long int newval);#include <pt-machine.h>
linuxthreads/pthread.c +8 -8
@@ -309,9 +309,9 @@pthread_descr self;/* First of all init __pthread_handles[0] and [1] if needed. */ -# if __LT_SPINLOCK_INIT !=0 - __pthread_handles[0 ].h_lock = __LOCK_INITIALIZER; - __pthread_handles[1 ].h_lock = __LOCK_INITIALIZER; +# ifdef __LT_INITIALIZER_NOT_ZERO + __pthread_handles[0 ].h_lock = __LOCK_ALT_INITIALIZER; + __pthread_handles[1 ].h_lock = __LOCK_ALT_INITIALIZER;# endif # ifndef SHARED /* Unlike in the dynamically linked case the dynamic linker has not
@@ -334,7 +334,7 @@# endif /* self->p_start_args need not be initialized, it's all zero. */ self->p_userstack =1 ; -# if __LT_SPINLOCK_INIT !=0 +# ifdef __LT_INITIALIZER_NOT_ZERO self->p_resume_count = (struct pthread_atomic ) __ATOMIC_INITIALIZER;# endif self->p_alloca_cutoff = __MAX_ALLOCA_CUTOFF;
@@ -346,9 +346,9 @@ __pthread_handles[0 ].h_descr = self;#else /* First of all init __pthread_handles[0] and [1]. */ -# if __LT_SPINLOCK_INIT !=0 - __pthread_handles[0 ].h_lock = __LOCK_INITIALIZER; - __pthread_handles[1 ].h_lock = __LOCK_INITIALIZER; +# ifdef __LT_INITIALIZER_NOT_ZERO + __pthread_handles[0 ].h_lock = __LOCK_ALT_INITIALIZER; + __pthread_handles[1 ].h_lock = __LOCK_ALT_INITIALIZER;# endif __pthread_handles[0 ].h_descr = &__pthread_initial_thread; __pthread_handles[1 ].h_descr = &__pthread_manager_thread;
@@ -572,7 +572,7 @@# endif tcb->p_start_args = (struct pthread_start_args )PTHREAD_START_ARGS_INITIALIZER (__pthread_manager); tcb->p_nr =1 ; -# if __LT_SPINLOCK_INIT !=0 +# ifdef __LT_INITIALIZER_NOT_ZERO self->p_resume_count = (struct pthread_atomic ) __ATOMIC_INITIALIZER;# endif tcb->p_alloca_cutoff =PTHREAD_STACK_MIN /4 ;
linuxthreads/spinlock.c +12 -12
@@ -24,9 +24,9 @@#include "spinlock.h" #include "restart.h" -static void __pthread_acquire (int * spinlock); +static void __pthread_acquire (__atomic_lock_t * spinlock); -static inline void __pthread_release (int * spinlock) +static inline void __pthread_release (__atomic_lock_t * spinlock) {WRITE_MEMORY_BARRIER (); *spinlock = __LT_SPINLOCK_INIT;
@@ -269,11 +269,11 @@struct wait_node {struct wait_node *next;/* Next node in null terminated linked list */ pthread_descr thr;/* The thread waiting with this node */ -int abandoned;/* Atomic flag */ +__atomic_lock_t abandoned;/* Atomic flag */ };static long wait_node_free_list; -static int wait_node_free_list_spinlock; +__pthread_lock_define_initialized (static, wait_node_free_list_spinlock);/* Allocate a new node from the head of the free list using an atomic operation, or else using malloc if that list is empty. A fundamental
@@ -376,7 +376,7 @@if (self ==NULL ) self =thread_self (); - wait_node.abandoned =0 ; + wait_node.abandoned = __LT_SPINLOCK_INIT; wait_node.next = (struct wait_node *) lock->__status; wait_node.thr = self; lock->__status = (long ) &wait_node;
@@ -402,7 +402,7 @@ wait_node.thr = self; newstatus = (long ) &wait_node; } - wait_node.abandoned =0 ; + wait_node.abandoned = __LT_SPINLOCK_INIT; wait_node.next = (struct wait_node *) oldstatus;/* Make sure the store in wait_node.next completes before performing the compare-and-swap */
@@ -451,7 +451,7 @@if (self ==NULL ) self =thread_self (); - p_wait_node->abandoned =0 ; + p_wait_node->abandoned = __LT_SPINLOCK_INIT; p_wait_node->next = (struct wait_node *) lock->__status; p_wait_node->thr = self; lock->__status = (long ) p_wait_node;
@@ -474,7 +474,7 @@ p_wait_node->thr = self; newstatus = (long ) p_wait_node; } - p_wait_node->abandoned =0 ; + p_wait_node->abandoned = __LT_SPINLOCK_INIT; p_wait_node->next = (struct wait_node *) oldstatus;/* Make sure the store in wait_node.next completes before performing the compare-and-swap */
@@ -574,7 +574,7 @@while (p_node != (struct wait_node *)1 ) {int prio; -if (p_node->abandoned) { +if (lock_held (&p_node->abandoned)) {/* Remove abandoned node. */ #if definedTEST_FOR_COMPARE_AND_SWAP if (!__pthread_has_cas)
@@ -605,7 +605,7 @@ p_max_prio = p_node; } -/* This canno6 jump backward in the list, so no further read +/* This cannot jump backward in the list, so no further read barrier is needed. */ pp_node = &p_node->next; p_node = *pp_node;
@@ -662,7 +662,7 @@#if !definedHAS_COMPARE_AND_SWAP || definedTEST_FOR_COMPARE_AND_SWAP int __pthread_compare_and_swap (long * ptr,long oldval,long newval, -int * spinlock) +__atomic_lock_t * spinlock) {int res;
@@ -699,7 +699,7 @@- When nanosleep() returns, we try again, doing MAX_SPIN_COUNT sched_yield(), then sleeping again if needed. */ -static void __pthread_acquire (int * spinlock) +static void __pthread_acquire (__atomic_lock_t * spinlock) {int cnt =0 ;struct timespec tm;
linuxthreads/spinlock.h +20 -6
@@ -33,14 +33,28 @@#endif #endif +/* Define lock_held for all arches that don't need a modified copy. */ +#ifndef __LT_INITIALIZER_NOT_ZERO +# define lock_held (p) *(p) +#endif + +/* Initliazers for possibly complex structures */ +#ifdef __LT_INITIALIZER_NOT_ZERO +# define __pthread_lock_define_initialized (CLASS ,NAME ) \ + CLASS __atomic_lock_t NAME = __LT_SPINLOCK_ALT_INIT +#else +# define __pthread_lock_define_initialized (CLASS ,NAME ) \ + CLASS __atomic_lock_t NAME +#endif +#if defined(TEST_FOR_COMPARE_AND_SWAP )extern int __pthread_has_cas;extern int __pthread_compare_and_swap (long * ptr,long oldval,long newval, -int * spinlock); +__atomic_lock_t * spinlock);static inline int compare_and_swap (long * ptr,long oldval,long newval, -int * spinlock) +__atomic_lock_t * spinlock) {if (__builtin_expect (__pthread_has_cas,1 ))return __compare_and_swap (ptr, oldval, newval);
@@ -58,7 +72,7 @@static inline int compare_and_swap_with_release_semantics (long * ptr,long oldval, -long newval,int * spinlock) +long newval,__atomic_lock_t * spinlock) {return __compare_and_swap_with_release_semantics (ptr, oldval, newval);
@@ -67,7 +81,7 @@#endif static inline int compare_and_swap (long * ptr,long oldval,long newval, -int * spinlock) +__atomic_lock_t * spinlock) {return __compare_and_swap (ptr, oldval, newval); }
@@ -75,10 +89,10 @@#else extern int __pthread_compare_and_swap (long * ptr,long oldval,long newval, -int * spinlock); +__atomic_lock_t * spinlock);static inline int compare_and_swap (long * ptr,long oldval,long newval, -int * spinlock) +__atomic_lock_t * spinlock) {return __pthread_compare_and_swap (ptr, oldval, newval, spinlock); }
linuxthreads/sysdeps/hppa/pspinlock.c +11 -13
@@ -21,18 +21,20 @@#include <pthread.h> #include "internals.h" +/* LDCW, the only atomic read-write operation PA-RISC has. *sigh*. */ +#define __ldcw (a) ({ \ + unsigned __ret; \ + __asm__ __volatile__("ldcw 0(%1),%0" : "=r" (__ret) : "r" (a)); \ + __ret; \ +}) +int __pthread_spin_lock (pthread_spinlock_t *lock) { -unsigned int val; - -do - asmvolatile ("ldcw %1,%0" - :"=r" (val),"=m" (*lock) - :"m" (*lock)); -while (!val); +while (__ldcw (*lock) ==0 ) +while (*lock ==0 ) ; -return 0 ; +return 0 ; }weak_alias (__pthread_spin_lock, pthread_spin_lock)
@@ -40,11 +42,7 @@int __pthread_spin_trylock (pthread_spinlock_t *lock) { -unsigned int val; - - asmvolatile ("ldcw %1,%0" - :"=r" (val),"=m" (*lock) - :"m" (*lock)); +unsigned int val =__ldcw (*lock);return val ?0 :EBUSY ; }
linuxthreads/sysdeps/hppa/pt-machine.h +38 -8
76 lines not on this page · raw message
linuxthreads/sysdeps/pthread/bits/libc-lock.h +3 -3
@@ -64,12 +64,12 @@initialized locks must be set to one due to the lack of normal atomic operations.) */ -#if __LT_SPINLOCK_INIT ==0 +#ifdef __LT_INITIALIZER_NOT_ZERO# define __libc_lock_define_initialized (CLASS ,NAME ) \ - CLASS __libc_lock_t NAME; + CLASS __libc_lock_t NAME = PTHREAD_MUTEX_INITIALIZER;#else # define __libc_lock_define_initialized (CLASS ,NAME ) \ - CLASS __libc_lock_t NAME = PTHREAD_MUTEX_INITIALIZER; + CLASS __libc_lock_t NAME;#endif #define __libc_rwlock_define_initialized (CLASS ,NAME ) \
linuxthreads/sysdeps/pthread/bits/pthreadtypes.h +5 -3
@@ -22,12 +22,14 @@#define __need_schedparam#include <bits/sched.h> +typedef int __atomic_lock_t ; +/* Fast locks (not abstract because mutexes and conditions aren't abstract). */ struct _pthread_fastlock { -long int __status;/* "Free" or "taken" or head of waiting list */ -int __spinlock;/* Used by compare_and_swap emulation. Also, -adaptive SMP lock stores spin count here. */ +long int __status;/* "Free" or "taken" or head of waiting list */ +__atomic_lock_t __spinlock;/* Used by compare_and_swap emulation. Also, +adaptive SMP lock stores spin count here. */ };#ifndef _PTHREAD_DESCR_DEFINED
linuxthreads/sysdeps/unix/sysv/linux/hppa/bits/initspin.h +17 -5
@@ -19,9 +19,21 @@/* Initial value of a spinlock. PA-RISC only implements atomic load and clear so this must be non-zero. */ -#define __LT_SPINLOCK_INIT 1 +#define __LT_SPINLOCK_INIT ((__atomic_lock_t){ 1 }) + +/* Initillize global spinlocks without cast, generally macro wrapped */ +#define __LT_SPINLOCK_ALT_INIT { 1 } + +/* Macros for lock initializers, not using the above definition. +The above definition is not used in the case that static initializers +use this value. */ +#define __LOCK_INITIALIZER { { 1 }, 0 } +#define __ATOMIC_INITIALIZER { 0, { 1 } } + +/* Used to initialize _pthread_fastlock's in non-static case */ +#define __LOCK_ALT_INITIALIZER ((struct _pthread_fastlock){ __LT_SPINLOCK_INIT, 0 }) + +/* Tell the rest of the code that the initializer is non-zero without +explaining it's internal structure */ +#define __LT_INITIALIZER_NOT_ZERO -/* Macros for lock initializers, using the above definition. */ -#define __LOCK_INITIALIZER { 0, __LT_SPINLOCK_INIT } -#define __ALT_LOCK_INITIALIZER { 0, __LT_SPINLOCK_INIT } -#define __ATOMIC_INITIALIZER { 0, __LT_SPINLOCK_INIT }
linuxthreads/sysdeps/unix/sysv/linux/hppa/bits/pthreadtypes.h +146 -0
146 lines not on this page · raw message
linuxthreads/sysdeps/unix/sysv/linux/hppa/pt-initfini.c +66 -66
136 lines not on this page · raw message
sysdeps/hppa/dl-fptr.c +6 -4
@@ -30,7 +30,7 @@# include <pt-machine.h> /* Remember, we use 0 to mean that a lock is taken on PA-RISC. */ -static int __hppa_fptr_lock =1 ; +static __atomic_lock_t __hppa_fptr_lock = __LT_SPINLOCK_ALT_INIT;#endif /* Because ld.so is now versioned, these functions can be in their own
@@ -127,7 +127,7 @@#ifdef _LIBC_REENTRANT/* Release the lock. Again, remember, zero means the lock is taken! */ if (mem ==NULL ) - __hppa_fptr_lock =1 ; + __hppa_fptr_lock = __LT_SPINLOCK_INIT;#endif /* Set bit 30 to indicate to $$dyncall that this is a PLABEL. */
@@ -180,7 +180,7 @@#ifdef _LIBC_REENTRANT/* Release the lock. */ - __hppa_fptr_lock =1 ; + __hppa_fptr_lock = __LT_SPINLOCK_INIT;#endif }
@@ -190,6 +190,8 @@Elf32_Addr addr = (Elf32_Addr ) address;struct hppa_fptr *f; + address = (void *)((unsigned long )address &~3 );/* Clear the bottom two bits. See make_fptr. */ +#ifdef _LIBC_REENTRANT/* Make sure we are alone. */ while (testandset (&__hppa_fptr_lock));
@@ -204,7 +206,7 @@#ifdef _LIBC_REENTRANT/* Release the lock. */ - __hppa_fptr_lock =1 ; + __hppa_fptr_lock = __LT_SPINLOCK_INIT;#endif return addr;