Because the atomic sync functions in config/pa/linux-atomic.c are not lock free, we need to use __kernel_cmpxchg for the __sync_lock_release. This was found in glibc's pthread_spin_unlock
implementation.

Tested on hppa-unknown-linux-gnu.  Committed to trunk.

Dave
--
John David Anglin       dave.ang...@bell.net



2014-07-17  John David Anglin  <dang...@gcc.gnu.org>

        * config/pa/linux-atomic.c (__sync_lock_release_4): New.
        (SYNC_LOCK_RELEASE): Update to use __kernel_cmpxchg for release.
        Don't use SYNC_LOCK_RELEASE for int type.

Index: config/pa/linux-atomic.c
===================================================================
--- config/pa/linux-atomic.c    (revision 210671)
+++ config/pa/linux-atomic.c    (working copy)
@@ -293,13 +293,34 @@
 SUBWORD_TEST_AND_SET (unsigned short, 2)
 SUBWORD_TEST_AND_SET (unsigned char,  1)
 
+void HIDDEN
+__sync_lock_release_4 (int *ptr)
+{
+  int failure, oldval;
+
+  do {
+    oldval = *ptr;
+    failure = __kernel_cmpxchg (oldval, 0, ptr);
+  } while (failure != 0);
+}
+
 #define SYNC_LOCK_RELEASE(TYPE, WIDTH)                                 \
   void HIDDEN                                                          \
   __sync_lock_release_##WIDTH (TYPE *ptr)                              \
   {                                                                    \
-    *ptr = 0;                                                          \
+    int failure;                                                       \
+    unsigned int oldval, newval, shift, mask;                          \
+    int *wordptr = (int *) ((unsigned long) ptr & ~3);                 \
+                                                                       \
+    shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH;    \
+    mask = MASK_##WIDTH << shift;                                      \
+                                                                       \
+    do {                                                               \
+      oldval = *wordptr;                                               \
+      newval = oldval & ~mask;                                         \
+      failure = __kernel_cmpxchg (oldval, newval, wordptr);            \
+    } while (failure != 0);                                            \
   }
 
-SYNC_LOCK_RELEASE (int,   4)
 SYNC_LOCK_RELEASE (short, 2)
 SYNC_LOCK_RELEASE (char,  1)

Reply via email to