about summary refs log tree commit diff
path: root/REORG.TODO/sysdeps/unix/sysv/linux/hppa/internaltypes.h
diff options
context:
space:
mode:
Diffstat (limited to 'REORG.TODO/sysdeps/unix/sysv/linux/hppa/internaltypes.h')
-rw-r--r--REORG.TODO/sysdeps/unix/sysv/linux/hppa/internaltypes.h84
1 files changed, 84 insertions, 0 deletions
diff --git a/REORG.TODO/sysdeps/unix/sysv/linux/hppa/internaltypes.h b/REORG.TODO/sysdeps/unix/sysv/linux/hppa/internaltypes.h
new file mode 100644
index 0000000000..d6496579da
--- /dev/null
+++ b/REORG.TODO/sysdeps/unix/sysv/linux/hppa/internaltypes.h
@@ -0,0 +1,84 @@
+#include_next <internaltypes.h>
+#ifndef _INTERNAL_TYPES_H_HPPA_
+#define _INTERNAL_TYPES_H_HPPA_ 1
+#include <atomic.h>
+
+/* 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.__wseq = 0;						\
+  var->__data.__signals_sent = 0;					\
+  var->__data.__confirmed = 0;						\
+  var->__data.__generation = 0;						\
+  var->__data.__mutex = NULL;						\
+  var->__data.__quiescence_waiters = 0;					\
+  var->__data.__clockid = 0;						\
+  /* Clear __initializer last, to indicate initialization is done.  */	\
+  /* This synchronizes-with the acquire load below.  */			\
+  atomic_store_release (&var->__data.__initializer, 0);			\
+})
+
+#define cond_compat_check_and_clear(var) \
+({								\
+  int v;							\
+  int *value = &var->__data.__initializer;			\
+  /* This synchronizes-with the release store above.  */	\
+  while ((v = atomic_load_acquire (value)) != 0)		\
+    {								\
+      if (v == 1						\
+	  /* Relaxed MO is fine; it only matters who's first.  */        \
+	  && atomic_compare_exchange_acquire_weak_relaxed (value, 1, 2)) \
+	{							\
+	  /* We're first; initialize structure.  */		\
+	  cond_compat_clear (var);				\
+	  break;						\
+	}							\
+      else							\
+	/* Yield before we re-check initialization status.  */	\
+	sched_yield ();						\
+    }								\
+})
+
+#endif