#include_next #ifndef _INTERNAL_TYPES_H_HPPA_ #define _INTERNAL_TYPES_H_HPPA_ 1 #include /* In GLIBC 2.10 HPPA switched from Linuxthreads to NPTL, and in order to maintain ABI compatibility with pthread_cond_t, some care had to be taken. The NPTL pthread_cond_t grew in size. When HPPA switched to NPTL, we dropped the use of ldcw, and switched to the kernel helper routine for compare-and-swap. This allowed HPPA to use the 4-word 16-byte aligned lock words, and alignment words to store the additional pthread_cond_t data. Once organized properly the new NPTL pthread_cond_t was 1 word smaller than the Linuxthreads version. However, we were faced with the case that users may have initialized the pthread_cond_t with PTHREAD_COND_INITIALIZER. In this case, the first four words were set to one, and must be cleared before any NPTL code used these words. We didn't want to use LDCW, because it continues to be a source of bugs when applications memset pthread_cond_t to all zeroes by accident. This works on all other architectures where lock words are unlocked at zero. Remember that because of the semantics of LDCW, a locked word is set to zero, and an unlocked word is set to 1. Instead we used atomic_compare_and_exchange_val_acq, but we couldn't use this on any of the pthread_cond_t words, otherwise it might interfere with the current operation of the structure. To solve this problem we used the left over word. If the stucture was initialized by a legacy Linuxthread PTHREAD_COND_INITIALIZER it contained a 1, and this indicates that the structure requires zeroing for NPTL. The first thread to come upon a pthread_cond_t with a 1 in the __initializer field, will compare-and-swap the value, placing a 2 there which will cause all other threads using the same pthread_cond_t to wait for the completion of the initialization. Lastly, we use a store (with memory barrier) to change __initializer from 2 to 0. Note that the store is strongly ordered, but we use the PA 1.1 compatible form which is ",ma" with zero offset. In the future, when the application is recompiled with NPTL PTHREAD_COND_INITIALIZER it will be a quick compare-and-swap, which fails because __initializer is zero, and the structure will be used as is correctly. */ #define cond_compat_clear(var) \ ({ \ int tmp = 0; \ var->__data.__lock = 0; \ var->__data.__futex = 0; \ var->__data.__mutex = NULL; \ /* Clear __initializer last, to indicate initialization is done. */ \ __asm__ __volatile__ ("stw,ma %1,0(%0)" \ : : "r" (&var->__data.__initializer), "r" (tmp) : "memory"); \ }) #define cond_compat_check_and_clear(var) \ ({ \ int ret; \ volatile int *value = &var->__data.__initializer; \ if ((ret = atomic_compare_and_exchange_val_acq(value, 2, 1))) \ { \ if (ret == 1) \ { \ /* Initialize structure. */ \ cond_compat_clear (var); \ } \ else \ { \ /* Yield until structure is initialized. */ \ while (*value == 2) sched_yield (); \ } \ } \ }) #endif