[kdbus] KDBUS_ITEM_PAYLOAD_OFF items are (once again) relative to msg header
[platform/upstream/glib.git] / glib / gatomic.c
index 1e83f19..30a5c5d 100644 (file)
@@ -12,9 +12,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  *
  * Author: Ryan Lortie <desrt@desrt.ca>
  */
  * hardware memory barrier.  Acquire and release or producer and
  * consumer barrier semantics are not available through this API.
  *
- * On GCC, these macros are implemented using GCC intrinsic operations.
- * On non-GCC compilers they will evaluate to function calls to
- * functions implemented by GLib.
- *
- * If GLib itself was compiled with GCC then these functions will again
- * be implemented by the GCC intrinsics.  On Windows without GCC, the
- * interlocked API is used to implement the functions.
- *
- * With non-GCC compilers on non-Windows systems, the functions are
- * currently incapable of implementing true atomic operations --
- * instead, they fallback to holding a global lock while performing the
- * operation.  This provides atomicity between the threads of one
- * process, but not between separate processes.  For this reason, one
- * should exercise caution when attempting to use these options on
- * shared memory regions.
- *
  * It is very important that all accesses to a particular integer or
  * pointer be performed using only this API and that different sizes of
  * operation are not mixed or used on overlapping memory regions.  Never
  * fall outside of simple reference counting patterns are prone to
  * subtle bugs and occasionally undefined behaviour.  It is also worth
  * noting that since all of these operations require global
- * synchronisation of the entire machine, they can be quite slow.  In
- * the case of performing multiple atomic operations it can often be
+ * synchronisation of the entire machine, they can be quite slow.  In * the case of performing multiple atomic operations it can often be
  * faster to simply acquire a mutex lock around the critical area,
  * perform the operations normally and then release the lock.
  **/
 
-#ifdef G_ATOMIC_OP_USE_GCC_BUILTINS
+/**
+ * G_ATOMIC_LOCK_FREE:
+ *
+ * This macro is defined if the atomic operations of GLib are
+ * implemented using real hardware atomic operations.  This means that
+ * the GLib atomic API can be used between processes and safely mixed
+ * with other (hardware) atomic APIs.
+ *
+ * If this macro is not defined, the atomic operations may be
+ * emulated using a mutex.  In that case, the GLib atomic operations are
+ * only atomic relative to themselves and within a single process.
+ **/
 
-#ifndef __GNUC__
-#error Using GCC builtin atomic ops, but not compiling with GCC?
-#endif
+/* NOTE CAREFULLY:
+ *
+ * This file is the lowest-level part of GLib.
+ *
+ * Other lowlevel parts of GLib (threads, slice allocator, g_malloc,
+ * messages, etc) call into these functions and macros to get work done.
+ *
+ * As such, these functions can not call back into any part of GLib
+ * without risking recursion.
+ */
+
+#ifdef G_ATOMIC_LOCK_FREE
+
+/* if G_ATOMIC_LOCK_FREE was defined by ./configure then we MUST
+ * implement the atomic operations in a lock-free manner.
+ */
 
+#if defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
 /**
  * g_atomic_int_get:
  * @atomic: a pointer to a #gint or #guint
  * Since: 2.4
  **/
 gint
-(g_atomic_int_get) (volatile gint *atomic)
+(g_atomic_int_get) (const volatile gint *atomic)
 {
   return g_atomic_int_get (atomic);
 }
@@ -132,8 +138,7 @@ void
  *
  * Increments the value of @atomic by 1.
  *
- * Think of this operation as an atomic version of
- * <literal>{ *@atomic += 1; }</literal>
+ * Think of this operation as an atomic version of `{ *atomic += 1; }`.
  *
  * This call acts as a full compiler and hardware memory barrier.
  *
@@ -152,7 +157,7 @@ void
  * Decrements the value of @atomic by 1.
  *
  * Think of this operation as an atomic version of
- * <literal>{ *@atomic -= 1; return (*@atomic == 0); }</literal>
+ * `{ *atomic -= 1; return (*atomic == 0); }`.
  *
  * This call acts as a full compiler and hardware memory barrier.
  *
@@ -178,7 +183,7 @@ gboolean
  * This compare and exchange is done atomically.
  *
  * Think of this operation as an atomic version of
- * <literal>{ if (*@atomic == @oldval) { *@atomic = @newval; return TRUE; } else return FALSE; }</literal>
+ * `{ if (*atomic == oldval) { *atomic = newval; return TRUE; } else return FALSE; }`.
  *
  * This call acts as a full compiler and hardware memory barrier.
  *
@@ -202,7 +207,7 @@ gboolean
  * Atomically adds @val to the value of @atomic.
  *
  * Think of this operation as an atomic version of
- * <literal>{ tmp = *atomic; *@atomic += @val; return tmp; }</literal>
+ * `{ tmp = *atomic; *atomic += val; return tmp; }`.
  *
  * This call acts as a full compiler and hardware memory barrier.
  *
@@ -231,7 +236,7 @@ gint
  * This call acts as a full compiler and hardware memory barrier.
  *
  * Think of this operation as an atomic version of
- * <literal>{ tmp = *atomic; *@atomic &= @val; return tmp; }</literal>
+ * `{ tmp = *atomic; *atomic &= val; return tmp; }`.
  *
  * Returns: the value of @atomic before the operation, unsigned
  *
@@ -253,7 +258,7 @@ guint
  * storing the result back in @atomic.
  *
  * Think of this operation as an atomic version of
- * <literal>{ tmp = *atomic; *@atomic |= @val; return tmp; }</literal>
+ * `{ tmp = *atomic; *atomic |= val; return tmp; }`.
  *
  * This call acts as a full compiler and hardware memory barrier.
  *
@@ -277,7 +282,7 @@ guint
  * storing the result back in @atomic.
  *
  * Think of this operation as an atomic version of
- * <literal>{ tmp = *atomic; *@atomic ^= @val; return tmp; }</literal>
+ * `{ tmp = *atomic; *atomic ^= val; return tmp; }`.
  *
  * This call acts as a full compiler and hardware memory barrier.
  *
@@ -307,9 +312,9 @@ guint
  * Since: 2.4
  **/
 gpointer
-(g_atomic_pointer_get) (volatile void *atomic)
+(g_atomic_pointer_get) (const volatile void *atomic)
 {
-  return g_atomic_pointer_get ((volatile gpointer *) atomic);
+  return g_atomic_pointer_get ((const volatile gpointer *) atomic);
 }
 
 /**
@@ -343,7 +348,7 @@ void
  * This compare and exchange is done atomically.
  *
  * Think of this operation as an atomic version of
- * <literal>{ if (*@atomic == @oldval) { *@atomic = @newval; return TRUE; } else return FALSE; }</literal>
+ * `{ if (*atomic == oldval) { *atomic = newval; return TRUE; } else return FALSE; }`.
  *
  * This call acts as a full compiler and hardware memory barrier.
  *
@@ -368,7 +373,7 @@ gboolean
  * Atomically adds @val to the value of @atomic.
  *
  * Think of this operation as an atomic version of
- * <literal>{ tmp = *atomic; *@atomic += @val; return tmp; }</literal>
+ * `{ tmp = *atomic; *atomic += val; return tmp; }`.
  *
  * This call acts as a full compiler and hardware memory barrier.
  *
@@ -392,7 +397,7 @@ gssize
  * storing the result back in @atomic.
  *
  * Think of this operation as an atomic version of
- * <literal>{ tmp = *atomic; *@atomic &= @val; return tmp; }</literal>
+ * `{ tmp = *atomic; *atomic &= val; return tmp; }`.
  *
  * This call acts as a full compiler and hardware memory barrier.
  *
@@ -416,7 +421,7 @@ gsize
  * storing the result back in @atomic.
  *
  * Think of this operation as an atomic version of
- * <literal>{ tmp = *atomic; *@atomic |= @val; return tmp; }</literal>
+ * `{ tmp = *atomic; *atomic |= val; return tmp; }`.
  *
  * This call acts as a full compiler and hardware memory barrier.
  *
@@ -440,7 +445,7 @@ gsize
  * storing the result back in @atomic.
  *
  * Think of this operation as an atomic version of
- * <literal>{ tmp = *atomic; *@atomic ^= @val; return tmp; }</literal>
+ * `{ tmp = *atomic; *atomic ^= val; return tmp; }`.
  *
  * This call acts as a full compiler and hardware memory barrier.
  *
@@ -455,20 +460,70 @@ gsize
   return g_atomic_pointer_xor ((volatile gpointer *) atomic, val);
 }
 
-#elif defined (G_PLATFORM_WIN32) && defined(HAVE_WIN32_BUILTINS_FOR_ATOMIC_OPERATIONS)
+#elif defined (G_PLATFORM_WIN32)
 
 #include <windows.h>
-#if !defined(_M_AMD64) && !defined (_M_IA64) && !defined(_M_X64)
+#if !defined(_M_AMD64) && !defined (_M_IA64) && !defined(_M_X64) && !(defined _MSC_VER && _MSC_VER <= 1200)
 #define InterlockedAnd _InterlockedAnd
 #define InterlockedOr _InterlockedOr
 #define InterlockedXor _InterlockedXor
 #endif
 
+#if !defined (_MSC_VER) || _MSC_VER <= 1200
+#include "gmessages.h"
+/* Inlined versions for older compiler */
+static LONG
+_gInterlockedAnd (volatile guint *atomic,
+                  guint           val)
+{
+  LONG i, j;
+
+  j = *atomic;
+  do {
+    i = j;
+    j = InterlockedCompareExchange(atomic, i & val, i);
+  } while (i != j);
+
+  return j;
+}
+#define InterlockedAnd(a,b) _gInterlockedAnd(a,b)
+static LONG
+_gInterlockedOr (volatile guint *atomic,
+                 guint           val)
+{
+  LONG i, j;
+
+  j = *atomic;
+  do {
+    i = j;
+    j = InterlockedCompareExchange(atomic, i | val, i);
+  } while (i != j);
+
+  return j;
+}
+#define InterlockedOr(a,b) _gInterlockedOr(a,b)
+static LONG
+_gInterlockedXor (volatile guint *atomic,
+                  guint           val)
+{
+  LONG i, j;
+
+  j = *atomic;
+  do {
+    i = j;
+    j = InterlockedCompareExchange(atomic, i ^ val, i);
+  } while (i != j);
+
+  return j;
+}
+#define InterlockedXor(a,b) _gInterlockedXor(a,b)
+#endif
+
 /*
  * http://msdn.microsoft.com/en-us/library/ms684122(v=vs.85).aspx
  */
 gint
-(g_atomic_int_get) (volatile gint *atomic)
+(g_atomic_int_get) (const volatile gint *atomic)
 {
   MemoryBarrier ();
   return *atomic;
@@ -532,9 +587,9 @@ guint
 
 
 gpointer
-(g_atomic_pointer_get) (volatile void *atomic)
+(g_atomic_pointer_get) (const volatile void *atomic)
 {
-  volatile gpointer *ptr = atomic;
+  const volatile gpointer *ptr = atomic;
 
   MemoryBarrier ();
   return *ptr;
@@ -601,21 +656,35 @@ gsize
   return InterlockedXor (atomic, val);
 #endif
 }
-
 #else
 
-#include "gthread.h"
+/* This error occurs when ./configure decided that we should be capable
+ * of lock-free atomics but we find at compile-time that we are not.
+ */
+#error G_ATOMIC_LOCK_FREE defined, but incapable of lock-free atomics.
 
-static GStaticMutex g_atomic_lock;
+#endif /* defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) */
+
+#else /* G_ATOMIC_LOCK_FREE */
+
+/* We are not permitted to call into any GLib functions from here, so we
+ * can not use GMutex.
+ *
+ * Fortunately, we already take care of the Windows case above, and all
+ * non-Windows platforms on which glib runs have pthreads.  Use those.
+ */
+#include <pthread.h>
+
+static pthread_mutex_t g_atomic_lock = PTHREAD_MUTEX_INITIALIZER;
 
 gint
-(g_atomic_int_get) (volatile gint *atomic)
+(g_atomic_int_get) (const volatile gint *atomic)
 {
   gint value;
 
-  g_static_mutex_lock (&g_atomic_lock);
+  pthread_mutex_lock (&g_atomic_lock);
   value = *atomic;
-  g_static_mutex_unlock (&g_atomic_lock);
+  pthread_mutex_unlock (&g_atomic_lock);
 
   return value;
 }
@@ -624,17 +693,17 @@ void
 (g_atomic_int_set) (volatile gint *atomic,
                     gint           value)
 {
-  g_static_mutex_lock (&g_atomic_lock);
+  pthread_mutex_lock (&g_atomic_lock);
   *atomic = value;
-  g_static_mutex_unlock (&g_atomic_lock);
+  pthread_mutex_unlock (&g_atomic_lock);
 }
 
 void
 (g_atomic_int_inc) (volatile gint *atomic)
 {
-  g_static_mutex_lock (&g_atomic_lock);
+  pthread_mutex_lock (&g_atomic_lock);
   (*atomic)++;
-  g_static_mutex_unlock (&g_atomic_lock);
+  pthread_mutex_unlock (&g_atomic_lock);
 }
 
 gboolean
@@ -642,9 +711,9 @@ gboolean
 {
   gboolean is_zero;
 
-  g_static_mutex_lock (&g_atomic_lock);
+  pthread_mutex_lock (&g_atomic_lock);
   is_zero = --(*atomic) == 0;
-  g_static_mutex_unlock (&g_atomic_lock);
+  pthread_mutex_unlock (&g_atomic_lock);
 
   return is_zero;
 }
@@ -656,12 +725,12 @@ gboolean
 {
   gboolean success;
 
-  g_static_mutex_lock (&g_atomic_lock);
+  pthread_mutex_lock (&g_atomic_lock);
 
   if ((success = (*atomic == oldval)))
     *atomic = newval;
 
-  g_static_mutex_unlock (&g_atomic_lock);
+  pthread_mutex_unlock (&g_atomic_lock);
 
   return success;
 }
@@ -672,10 +741,10 @@ gint
 {
   gint oldval;
 
-  g_static_mutex_lock (&g_atomic_lock);
+  pthread_mutex_lock (&g_atomic_lock);
   oldval = *atomic;
   *atomic = oldval + val;
-  g_static_mutex_unlock (&g_atomic_lock);
+  pthread_mutex_unlock (&g_atomic_lock);
 
   return oldval;
 }
@@ -686,10 +755,10 @@ guint
 {
   guint oldval;
 
-  g_static_mutex_lock (&g_atomic_lock);
+  pthread_mutex_lock (&g_atomic_lock);
   oldval = *atomic;
   *atomic = oldval & val;
-  g_static_mutex_unlock (&g_atomic_lock);
+  pthread_mutex_unlock (&g_atomic_lock);
 
   return oldval;
 }
@@ -700,10 +769,10 @@ guint
 {
   guint oldval;
 
-  g_static_mutex_lock (&g_atomic_lock);
+  pthread_mutex_lock (&g_atomic_lock);
   oldval = *atomic;
   *atomic = oldval | val;
-  g_static_mutex_unlock (&g_atomic_lock);
+  pthread_mutex_unlock (&g_atomic_lock);
 
   return oldval;
 }
@@ -714,24 +783,24 @@ guint
 {
   guint oldval;
 
-  g_static_mutex_lock (&g_atomic_lock);
+  pthread_mutex_lock (&g_atomic_lock);
   oldval = *atomic;
   *atomic = oldval ^ val;
-  g_static_mutex_unlock (&g_atomic_lock);
+  pthread_mutex_unlock (&g_atomic_lock);
 
   return oldval;
 }
 
 
 gpointer
-(g_atomic_pointer_get) (volatile void *atomic)
+(g_atomic_pointer_get) (const volatile void *atomic)
 {
-  volatile gpointer *ptr = atomic;
+  const volatile gpointer *ptr = atomic;
   gpointer value;
 
-  g_static_mutex_lock (&g_atomic_lock);
+  pthread_mutex_lock (&g_atomic_lock);
   value = *ptr;
-  g_static_mutex_unlock (&g_atomic_lock);
+  pthread_mutex_unlock (&g_atomic_lock);
 
   return value;
 }
@@ -742,9 +811,9 @@ void
 {
   volatile gpointer *ptr = atomic;
 
-  g_static_mutex_lock (&g_atomic_lock);
+  pthread_mutex_lock (&g_atomic_lock);
   *ptr = newval;
-  g_static_mutex_unlock (&g_atomic_lock);
+  pthread_mutex_unlock (&g_atomic_lock);
 }
 
 gboolean
@@ -755,12 +824,12 @@ gboolean
   volatile gpointer *ptr = atomic;
   gboolean success;
 
-  g_static_mutex_lock (&g_atomic_lock);
+  pthread_mutex_lock (&g_atomic_lock);
 
   if ((success = (*ptr == oldval)))
     *ptr = newval;
 
-  g_static_mutex_unlock (&g_atomic_lock);
+  pthread_mutex_unlock (&g_atomic_lock);
 
   return success;
 }
@@ -772,10 +841,10 @@ gssize
   volatile gssize *ptr = atomic;
   gssize oldval;
 
-  g_static_mutex_lock (&g_atomic_lock);
+  pthread_mutex_lock (&g_atomic_lock);
   oldval = *ptr;
   *ptr = oldval + val;
-  g_static_mutex_unlock (&g_atomic_lock);
+  pthread_mutex_unlock (&g_atomic_lock);
 
   return oldval;
 }
@@ -787,10 +856,10 @@ gsize
   volatile gsize *ptr = atomic;
   gsize oldval;
 
-  g_static_mutex_lock (&g_atomic_lock);
+  pthread_mutex_lock (&g_atomic_lock);
   oldval = *ptr;
   *ptr = oldval & val;
-  g_static_mutex_unlock (&g_atomic_lock);
+  pthread_mutex_unlock (&g_atomic_lock);
 
   return oldval;
 }
@@ -802,10 +871,10 @@ gsize
   volatile gsize *ptr = atomic;
   gsize oldval;
 
-  g_static_mutex_lock (&g_atomic_lock);
+  pthread_mutex_lock (&g_atomic_lock);
   oldval = *ptr;
   *ptr = oldval | val;
-  g_static_mutex_unlock (&g_atomic_lock);
+  pthread_mutex_unlock (&g_atomic_lock);
 
   return oldval;
 }
@@ -817,10 +886,10 @@ gsize
   volatile gsize *ptr = atomic;
   gsize oldval;
 
-  g_static_mutex_lock (&g_atomic_lock);
+  pthread_mutex_lock (&g_atomic_lock);
   oldval = *ptr;
   *ptr = oldval ^ val;
-  g_static_mutex_unlock (&g_atomic_lock);
+  pthread_mutex_unlock (&g_atomic_lock);
 
   return oldval;
 }