glib/libglib/src/gatomic.c
changeset 0 e4d67989cc36
child 12 8f46d5fb6bec
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     1 /* GLIB - Library of useful routines for C programming
       
     2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
       
     3  *
       
     4  * g_atomic_*: atomic operations.
       
     5  * Copyright (C) 2003 Sebastian Wilhelmi
       
     6  * Portions copyright (c) 2006 Nokia Corporation.  All rights reserved.
       
     7  *
       
     8  * This library is free software; you can redistribute it and/or
       
     9  * modify it under the terms of the GNU Lesser General Public
       
    10  * License as published by the Free Software Foundation; either
       
    11  * version 2 of the License, or (at your option) any later version.
       
    12  *
       
    13  * This library is distributed in the hope that it will be useful,
       
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    16  * Lesser General Public License for more details.
       
    17  *
       
    18  * You should have received a copy of the GNU Lesser General Public
       
    19  * License along with this library; if not, write to the
       
    20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    21  * Boston, MA 02111-1307, USA.
       
    22  */
       
    23  
       
    24 #include "config.h"
       
    25 
       
    26 #include "glib.h"
       
    27 #include "gthreadinit.h"
       
    28 #include "galias.h"
       
    29 
       
    30 #ifdef __SYMBIAN32__
       
    31 #include <glib_wsd.h>
       
    32 #endif /* __SYMBIAN32__ */
       
    33 
       
    34 #if EMULATOR
       
    35 #define g_thread_functions_for_glib_use (*_g_thread_functions_for_glib_use())
       
    36 #define g_thread_use_default_impl (*_g_thread_use_default_impl())
       
    37 #endif /* EMULATOR */
       
    38 
       
    39 
       
    40 #if defined (__GNUC__)
       
    41 # if defined (G_ATOMIC_I486)
       
    42 /* Adapted from CVS version 1.10 of glibc's sysdeps/i386/i486/bits/atomic.h 
       
    43  */
       
    44 EXPORT_C gint
       
    45 g_atomic_int_exchange_and_add (volatile gint *atomic, 
       
    46 			       gint           val)
       
    47 {
       
    48   gint result;
       
    49 
       
    50   __asm__ __volatile__ ("lock; xaddl %0,%1"
       
    51                         : "=r" (result), "=m" (*atomic) 
       
    52 			: "0" (val), "m" (*atomic));
       
    53   return result;
       
    54 }
       
    55  
       
    56 EXPORT_C void
       
    57 g_atomic_int_add (volatile gint *atomic, 
       
    58 		  gint           val)
       
    59 {
       
    60   __asm__ __volatile__ ("lock; addl %1,%0"
       
    61 			: "=m" (*atomic) 
       
    62 			: "ir" (val), "m" (*atomic));
       
    63 }
       
    64 
       
    65 EXPORT_C gboolean
       
    66 g_atomic_int_compare_and_exchange (volatile gint *atomic, 
       
    67 				   gint           oldval, 
       
    68 				   gint           newval)
       
    69 {
       
    70   gint result;
       
    71  
       
    72   __asm__ __volatile__ ("lock; cmpxchgl %2, %1"
       
    73 			: "=a" (result), "=m" (*atomic)
       
    74 			: "r" (newval), "m" (*atomic), "0" (oldval)); 
       
    75 
       
    76   return result == oldval;
       
    77 }
       
    78 
       
    79 /* The same code as above, as on i386 gpointer is 32 bit as well.
       
    80  * Duplicating the code here seems more natural than casting the
       
    81  * arguments and calling the former function */
       
    82 
       
    83 EXPORT_C gboolean
       
    84 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
       
    85 				       gpointer           oldval, 
       
    86 				       gpointer           newval)
       
    87 {
       
    88   gpointer result;
       
    89  
       
    90   __asm__ __volatile__ ("lock; cmpxchgl %2, %1"
       
    91 			: "=a" (result), "=m" (*atomic)
       
    92 			: "r" (newval), "m" (*atomic), "0" (oldval)); 
       
    93 
       
    94   return result == oldval;
       
    95 }
       
    96 
       
    97 # elif defined (G_ATOMIC_SPARCV9)
       
    98 /* Adapted from CVS version 1.3 of glibc's sysdeps/sparc/sparc64/bits/atomic.h
       
    99  */
       
   100 #  define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval)			\
       
   101   ({ 									\
       
   102      gint __result;							\
       
   103      __asm__ __volatile__ ("cas [%4], %2, %0"				\
       
   104                            : "=r" (__result), "=m" (*(atomic))		\
       
   105                            : "r" (oldval), "m" (*(atomic)), "r" (atomic),\
       
   106                            "0" (newval));				\
       
   107      __result == oldval;						\
       
   108   })
       
   109 
       
   110 #  if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
       
   111 EXPORT_C gboolean
       
   112 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
       
   113 				       gpointer           oldval, 
       
   114 				       gpointer           newval)
       
   115 {
       
   116   gpointer result;
       
   117   __asm__ __volatile__ ("cas [%4], %2, %0"
       
   118 			: "=r" (result), "=m" (*atomic)
       
   119 			: "r" (oldval), "m" (*atomic), "r" (atomic),
       
   120 			"0" (newval));
       
   121   return result == oldval;
       
   122 }
       
   123 #  elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
       
   124 EXPORT_C gboolean
       
   125 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
       
   126 				       gpointer           oldval, 
       
   127 				       gpointer           newval)
       
   128 {
       
   129   gpointer result;
       
   130   gpointer *a = atomic;
       
   131   __asm__ __volatile__ ("casx [%4], %2, %0"
       
   132 			: "=r" (result), "=m" (*a)
       
   133 			: "r" (oldval), "m" (*a), "r" (a),
       
   134 			"0" (newval));
       
   135   return result == oldval;
       
   136 }
       
   137 #  else /* What's that */
       
   138 #    error "Your system has an unsupported pointer size"
       
   139 #  endif /* GLIB_SIZEOF_VOID_P */
       
   140 #  define G_ATOMIC_MEMORY_BARRIER					\
       
   141   __asm__ __volatile__ ("membar #LoadLoad | #LoadStore"			\
       
   142                         " | #StoreLoad | #StoreStore" : : : "memory")
       
   143 
       
   144 # elif defined (G_ATOMIC_ALPHA)
       
   145 /* Adapted from CVS version 1.3 of glibc's sysdeps/alpha/bits/atomic.h
       
   146  */
       
   147 #  define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval)			\
       
   148   ({ 									\
       
   149      gint __result;							\
       
   150      gint __prev;							\
       
   151      __asm__ __volatile__ (						\
       
   152         "       mb\n"							\
       
   153         "1:     ldl_l   %0,%2\n"					\
       
   154         "       cmpeq   %0,%3,%1\n"					\
       
   155         "       beq     %1,2f\n"					\
       
   156         "       mov     %4,%1\n"					\
       
   157         "       stl_c   %1,%2\n"					\
       
   158         "       beq     %1,1b\n"					\
       
   159         "       mb\n"							\
       
   160         "2:"								\
       
   161         : "=&r" (__prev), 						\
       
   162           "=&r" (__result)						\
       
   163         : "m" (*(atomic)),						\
       
   164           "Ir" (oldval),						\
       
   165           "Ir" (newval)							\
       
   166         : "memory");							\
       
   167      __result != 0;							\
       
   168   })
       
   169 #  if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
       
   170 EXPORT_C gboolean
       
   171 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
       
   172 				       gpointer           oldval, 
       
   173 				       gpointer           newval)
       
   174 {
       
   175   gint result;
       
   176   gpointer prev;
       
   177   __asm__ __volatile__ (
       
   178         "       mb\n"
       
   179         "1:     ldl_l   %0,%2\n"
       
   180         "       cmpeq   %0,%3,%1\n"
       
   181         "       beq     %1,2f\n"
       
   182         "       mov     %4,%1\n"
       
   183         "       stl_c   %1,%2\n"
       
   184         "       beq     %1,1b\n"
       
   185         "       mb\n"
       
   186         "2:"
       
   187         : "=&r" (prev), 
       
   188           "=&r" (result)
       
   189         : "m" (*atomic),
       
   190           "Ir" (oldval),
       
   191           "Ir" (newval)
       
   192         : "memory");
       
   193   return result != 0;
       
   194 }
       
   195 #  elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
       
   196 EXPORT_C gboolean
       
   197 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
       
   198 				       gpointer           oldval, 
       
   199 				       gpointer           newval)
       
   200 {
       
   201   gint result;
       
   202   gpointer prev;
       
   203   __asm__ __volatile__ (
       
   204         "       mb\n"
       
   205         "1:     ldq_l   %0,%2\n"
       
   206         "       cmpeq   %0,%3,%1\n"
       
   207         "       beq     %1,2f\n"
       
   208         "       mov     %4,%1\n"
       
   209         "       stq_c   %1,%2\n"
       
   210         "       beq     %1,1b\n"
       
   211         "       mb\n"
       
   212         "2:"
       
   213         : "=&r" (prev), 
       
   214           "=&r" (result)
       
   215         : "m" (*atomic),
       
   216           "Ir" (oldval),
       
   217           "Ir" (newval)
       
   218         : "memory");
       
   219   return result != 0;
       
   220 }
       
   221 #  else /* What's that */
       
   222 #   error "Your system has an unsupported pointer size"
       
   223 #  endif /* GLIB_SIZEOF_VOID_P */
       
   224 #  define G_ATOMIC_MEMORY_BARRIER  __asm__ ("mb" : : : "memory")
       
   225 # elif defined (G_ATOMIC_X86_64)
       
   226 /* Adapted from CVS version 1.9 of glibc's sysdeps/x86_64/bits/atomic.h 
       
   227  */
       
   228 EXPORT_C gint
       
   229 g_atomic_int_exchange_and_add (volatile gint *atomic,
       
   230 			       gint           val)
       
   231 {
       
   232   gint result;
       
   233 
       
   234   __asm__ __volatile__ ("lock; xaddl %0,%1"
       
   235                         : "=r" (result), "=m" (*atomic) 
       
   236 			: "0" (val), "m" (*atomic));
       
   237   return result;
       
   238 }
       
   239  
       
   240 EXPORT_C void
       
   241 g_atomic_int_add (volatile gint *atomic, 
       
   242 		  gint           val)
       
   243 {
       
   244   __asm__ __volatile__ ("lock; addl %1,%0"
       
   245 			: "=m" (*atomic) 
       
   246 			: "ir" (val), "m" (*atomic));
       
   247 }
       
   248 
       
   249 EXPORT_C gboolean
       
   250 g_atomic_int_compare_and_exchange (volatile gint *atomic, 
       
   251 				   gint           oldval, 
       
   252 				   gint           newval)
       
   253 {
       
   254   gint result;
       
   255  
       
   256   __asm__ __volatile__ ("lock; cmpxchgl %2, %1"
       
   257 			: "=a" (result), "=m" (*atomic)
       
   258 			: "r" (newval), "m" (*atomic), "0" (oldval)); 
       
   259 
       
   260   return result == oldval;
       
   261 }
       
   262 
       
   263 EXPORT_C gboolean
       
   264 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
       
   265 				       gpointer           oldval, 
       
   266 				       gpointer           newval)
       
   267 {
       
   268   gpointer result;
       
   269  
       
   270   __asm__ __volatile__ ("lock; cmpxchgq %q2, %1"
       
   271 			: "=a" (result), "=m" (*atomic)
       
   272 			: "r" (newval), "m" (*atomic), "0" (oldval)); 
       
   273 
       
   274   return result == oldval;
       
   275 }
       
   276 
       
   277 # elif defined (G_ATOMIC_POWERPC)
       
   278 /* Adapted from CVS version 1.16 of glibc's sysdeps/powerpc/bits/atomic.h 
       
   279  * and CVS version 1.4 of glibc's sysdeps/powerpc/powerpc32/bits/atomic.h 
       
   280  * and CVS version 1.7 of glibc's sysdeps/powerpc/powerpc64/bits/atomic.h 
       
   281  */
       
   282 #   ifdef __OPTIMIZE__
       
   283 /* Non-optimizing compile bails on the following two asm statements
       
   284  * for reasons unknown to the author */
       
   285 EXPORT_C gint
       
   286 g_atomic_int_exchange_and_add (volatile gint *atomic, 
       
   287 			       gint           val)
       
   288 {
       
   289   gint result, temp;
       
   290   __asm__ __volatile__ ("1:       lwarx   %0,0,%3\n"
       
   291 			"         add     %1,%0,%4\n"
       
   292 			"         stwcx.  %1,0,%3\n"
       
   293 			"         bne-    1b"
       
   294 			: "=&b" (result), "=&r" (temp), "=m" (*atomic)
       
   295 			: "b" (atomic), "r" (val), "m" (*atomic)
       
   296 			: "cr0", "memory");
       
   297   return result;
       
   298 }
       
   299  
       
   300 /* The same as above, to save a function call repeated here */
       
   301 EXPORT_C void
       
   302 g_atomic_int_add (volatile gint *atomic, 
       
   303 		  gint           val)
       
   304 {
       
   305   gint result, temp;  
       
   306   __asm__ __volatile__ ("1:       lwarx   %0,0,%3\n"
       
   307 			"         add     %1,%0,%4\n"
       
   308 			"         stwcx.  %1,0,%3\n"
       
   309 			"         bne-    1b"
       
   310 			: "=&b" (result), "=&r" (temp), "=m" (*atomic)
       
   311 			: "b" (atomic), "r" (val), "m" (*atomic)
       
   312 			: "cr0", "memory");
       
   313 }
       
   314 #   else /* !__OPTIMIZE__ */
       
   315 EXPORT_C gint
       
   316 g_atomic_int_exchange_and_add (volatile gint *atomic, 
       
   317 			       gint           val)
       
   318 {
       
   319   gint result;
       
   320   do
       
   321     result = *atomic;
       
   322   while (!g_atomic_int_compare_and_exchange (atomic, result, result + val));
       
   323 
       
   324   return result;
       
   325 }
       
   326  
       
   327 EXPORT_C void
       
   328 g_atomic_int_add (volatile gint *atomic,
       
   329 		  gint           val)
       
   330 {
       
   331   gint result;
       
   332   do
       
   333     result = *atomic;
       
   334   while (!g_atomic_int_compare_and_exchange (atomic, result, result + val));
       
   335 }
       
   336 #   endif /* !__OPTIMIZE__ */
       
   337 
       
   338 #   if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
       
   339 EXPORT_C gboolean
       
   340 g_atomic_int_compare_and_exchange (volatile gint *atomic, 
       
   341 				   gint           oldval, 
       
   342 				   gint           newval)
       
   343 {
       
   344   gint result;
       
   345   __asm__ __volatile__ ("sync\n"
       
   346 			"1: lwarx   %0,0,%1\n"
       
   347 			"   subf.   %0,%2,%0\n"
       
   348 			"   bne     2f\n"
       
   349 			"   stwcx.  %3,0,%1\n"
       
   350 			"   bne-    1b\n"
       
   351 			"2: isync"
       
   352 			: "=&r" (result)
       
   353 			: "b" (atomic), "r" (oldval), "r" (newval)
       
   354 			: "cr0", "memory"); 
       
   355   return result == 0;
       
   356 }
       
   357 
       
   358 EXPORT_C gboolean
       
   359 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
       
   360 				       gpointer           oldval, 
       
   361 				       gpointer           newval)
       
   362 {
       
   363   gpointer result;
       
   364   __asm__ __volatile__ ("sync\n"
       
   365 			"1: lwarx   %0,0,%1\n"
       
   366 			"   subf.   %0,%2,%0\n"
       
   367 			"   bne     2f\n"
       
   368 			"   stwcx.  %3,0,%1\n"
       
   369 			"   bne-    1b\n"
       
   370 			"2: isync"
       
   371 			: "=&r" (result)
       
   372 			: "b" (atomic), "r" (oldval), "r" (newval)
       
   373 			: "cr0", "memory"); 
       
   374   return result == 0;
       
   375 }
       
   376 #   elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
       
   377 EXPORT_C gboolean
       
   378 g_atomic_int_compare_and_exchange (volatile gint *atomic,
       
   379 				   gint           oldval, 
       
   380 				   gint           newval)
       
   381 {
       
   382   gpointer result;
       
   383   __asm__ __volatile__ ("sync\n"
       
   384 			"1: lwarx   %0,0,%1\n"
       
   385 			"   extsw   %0,%0\n"
       
   386 			"   subf.   %0,%2,%0\n"
       
   387 			"   bne     2f\n"
       
   388 			"   stwcx.  %3,0,%1\n"
       
   389 			"   bne-    1b\n"
       
   390 			"2: isync"
       
   391 			: "=&r" (result)
       
   392 			: "b" (atomic), "r" (oldval), "r" (newval)
       
   393 			: "cr0", "memory"); 
       
   394   return result == 0;
       
   395 }
       
   396 
       
   397 EXPORT_C gboolean
       
   398 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
       
   399 				       gpointer           oldval, 
       
   400 				       gpointer           newval)
       
   401 {
       
   402   gpointer result;
       
   403   __asm__ __volatile__ ("sync\n"
       
   404 			"1: ldarx   %0,0,%1\n"
       
   405 			"   subf.   %0,%2,%0\n"
       
   406 			"   bne     2f\n"
       
   407 			"   stdcx.  %3,0,%1\n"
       
   408 			"   bne-    1b\n"
       
   409 			"2: isync"
       
   410 			: "=&r" (result)
       
   411 			: "b" (atomic), "r" (oldval), "r" (newval)
       
   412 			: "cr0", "memory"); 
       
   413   return result == 0;
       
   414 }
       
   415 #  else /* What's that */
       
   416 #   error "Your system has an unsupported pointer size"
       
   417 #  endif /* GLIB_SIZEOF_VOID_P */
       
   418 
       
   419 #  define G_ATOMIC_MEMORY_BARRIER __asm__ ("sync" : : : "memory")
       
   420 
       
   421 # elif defined (G_ATOMIC_IA64)
       
   422 /* Adapted from CVS version 1.8 of glibc's sysdeps/ia64/bits/atomic.h
       
   423  */
       
   424 EXPORT_C gint
       
   425 g_atomic_int_exchange_and_add (volatile gint *atomic,
       
   426 			       gint           val)
       
   427 {
       
   428   return __sync_fetch_and_add (atomic, val);
       
   429 }
       
   430  
       
   431 EXPORT_C void
       
   432 g_atomic_int_add (volatile gint *atomic, 
       
   433 		  gint val)
       
   434 {
       
   435   __sync_fetch_and_add (atomic, val);
       
   436 }
       
   437 
       
   438 EXPORT_C gboolean
       
   439 g_atomic_int_compare_and_exchange (volatile gint *atomic,
       
   440 				   gint           oldval, 
       
   441 				   gint           newval)
       
   442 {
       
   443   return __sync_bool_compare_and_swap (atomic, oldval, newval);
       
   444 }
       
   445 
       
   446 EXPORT_C gboolean
       
   447 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
       
   448 				       gpointer           oldval, 
       
   449 				       gpointer           newval)
       
   450 {
       
   451   return __sync_bool_compare_and_swap ((long *)atomic, 
       
   452 				       (long)oldval, (long)newval);
       
   453 }
       
   454 
       
   455 #  define G_ATOMIC_MEMORY_BARRIER __sync_synchronize ()
       
   456 # elif defined (G_ATOMIC_S390)
       
   457 /* Adapted from glibc's sysdeps/s390/bits/atomic.h
       
   458  */
       
   459 #  define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval)			\
       
   460   ({ 									\
       
   461      gint __result = oldval;					\
       
   462      __asm__ __volatile__ ("cs %0, %2, %1"				\
       
   463                            : "+d" (__result), "=Q" (*(atomic))		\
       
   464                            : "d" (newval), "m" (*(atomic)) : "cc" );	\
       
   465      __result == oldval;						\
       
   466   })
       
   467 
       
   468 #  if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
       
   469 EXPORT_C gboolean
       
   470 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
       
   471 				       gpointer           oldval,
       
   472 				       gpointer           newval)
       
   473 {
       
   474   gpointer result = oldval;
       
   475   __asm__ __volatile__ ("cs %0, %2, %1"
       
   476 			: "+d" (result), "=Q" (*(atomic))
       
   477 			: "d" (newval), "m" (*(atomic)) : "cc" );
       
   478   return result == oldval;
       
   479 }
       
   480 #  elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
       
   481 EXPORT_C gboolean
       
   482 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
       
   483 				       gpointer           oldval,
       
   484 				       gpointer           newval)
       
   485 {
       
   486   gpointer result = oldval;
       
   487   gpointer *a = atomic;
       
   488   __asm__ __volatile__ ("csg %0, %2, %1"
       
   489 			: "+d" (result), "=Q" (*a)
       
   490 			: "d" ((long)(newval)), "m" (*a) : "cc" );
       
   491   return result == oldval;
       
   492 }
       
   493 #  else /* What's that */
       
   494 #    error "Your system has an unsupported pointer size"
       
   495 #  endif /* GLIB_SIZEOF_VOID_P */
       
   496 # else /* !G_ATOMIC_IA64 */
       
   497 #  define DEFINE_WITH_MUTEXES
       
   498 # endif /* G_ATOMIC_IA64 */
       
   499 #else /* !__GNUC__ */
       
   500 # ifdef G_PLATFORM_WIN32
       
   501 #  define DEFINE_WITH_WIN32_INTERLOCKED
       
   502 # else
       
   503 #  define DEFINE_WITH_MUTEXES
       
   504 # endif
       
   505 #endif /* __GNUC__ */
       
   506 
       
   507 #ifdef DEFINE_WITH_WIN32_INTERLOCKED
       
   508 # include <windows.h>
       
   509 /* Following indicates that InterlockedCompareExchangePointer is
       
   510  * declared in winbase.h (included by windows.h) and needs to be
       
   511  * commented out if not true. It is defined iff WINVER > 0x0400,
       
   512  * which is usually correct but can be wrong if WINVER is set before
       
   513  * windows.h is included.
       
   514  */
       
   515 # if WINVER > 0x0400
       
   516 #  define HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER
       
   517 # endif
       
   518 
       
   519 EXPORT_C gint32   
       
   520 g_atomic_int_exchange_and_add (volatile gint32 *atomic,
       
   521 			       gint32           val)
       
   522 {
       
   523   return InterlockedExchangeAdd (atomic, val);
       
   524 }
       
   525 
       
   526 EXPORT_C void     
       
   527 g_atomic_int_add (volatile gint32 *atomic, 
       
   528 		  gint32           val)
       
   529 {
       
   530   InterlockedExchangeAdd (atomic, val);
       
   531 }
       
   532 
       
   533 EXPORT_C gboolean 
       
   534 g_atomic_int_compare_and_exchange (volatile gint32 *atomic,
       
   535 				   gint32           oldval,
       
   536 				   gint32           newval)
       
   537 {
       
   538 #ifndef HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER
       
   539   return (guint32) InterlockedCompareExchange ((PVOID*)atomic, 
       
   540                                                (PVOID)newval, 
       
   541                                                (PVOID)oldval) == oldval;
       
   542 #else
       
   543   return InterlockedCompareExchange (atomic, 
       
   544                                      newval, 
       
   545                                      oldval) == oldval;
       
   546 #endif
       
   547 }
       
   548 
       
   549 EXPORT_C gboolean 
       
   550 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
       
   551 				       gpointer           oldval,
       
   552 				       gpointer           newval)
       
   553 {
       
   554 # ifdef HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER
       
   555   return InterlockedCompareExchangePointer (atomic, newval, oldval) == oldval;
       
   556 # else
       
   557 #  if GLIB_SIZEOF_VOID_P != 4 /* no 32-bit system */
       
   558 #   error "InterlockedCompareExchangePointer needed"
       
   559 #  else
       
   560    return InterlockedCompareExchange (atomic, newval, oldval) == oldval;
       
   561 #  endif
       
   562 # endif
       
   563 }
       
   564 #endif /* DEFINE_WITH_WIN32_INTERLOCKED */
       
   565 
       
   566 #ifdef DEFINE_WITH_MUTEXES
       
   567 /* We have to use the slow, but safe locking method */
       
   568 
       
   569 #if EMULATOR
       
   570 
       
   571 PLS(g_atomic_mutex , gatomic,GMutex *)
       
   572 #define g_atomic_mutex (*FUNCTION_NAME(g_atomic_mutex,gatomic)())
       
   573 
       
   574 #else
       
   575 
       
   576 static GMutex *g_atomic_mutex; 
       
   577 
       
   578 #endif /* EMULATOR */
       
   579 
       
   580 EXPORT_C gint
       
   581 g_atomic_int_exchange_and_add (volatile gint *atomic, 
       
   582 			       gint           val)
       
   583 {
       
   584   gint result;
       
   585     
       
   586   g_mutex_lock (g_atomic_mutex);
       
   587   result = *atomic;
       
   588   *atomic += val;
       
   589   g_mutex_unlock (g_atomic_mutex);
       
   590 
       
   591   return result;
       
   592 }
       
   593 
       
   594 
       
   595 EXPORT_C void
       
   596 g_atomic_int_add (volatile gint *atomic,
       
   597 		  gint           val)
       
   598 {
       
   599   g_mutex_lock (g_atomic_mutex);
       
   600   *atomic += val;
       
   601   g_mutex_unlock (g_atomic_mutex);
       
   602 }
       
   603 
       
   604 EXPORT_C gboolean
       
   605 g_atomic_int_compare_and_exchange (volatile gint *atomic, 
       
   606 				   gint           oldval, 
       
   607 				   gint           newval)
       
   608 {
       
   609   gboolean result;
       
   610     
       
   611   g_mutex_lock (g_atomic_mutex);
       
   612   if (*atomic == oldval)
       
   613     {
       
   614       result = TRUE;
       
   615       *atomic = newval;
       
   616     }
       
   617   else
       
   618     result = FALSE;
       
   619   g_mutex_unlock (g_atomic_mutex);
       
   620 
       
   621   return result;
       
   622 }
       
   623 
       
   624 EXPORT_C gboolean
       
   625 g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
       
   626 				       gpointer           oldval, 
       
   627 				       gpointer           newval)
       
   628 {
       
   629   gboolean result;
       
   630     
       
   631   g_mutex_lock (g_atomic_mutex);
       
   632   if (*atomic == oldval)
       
   633     {
       
   634       result = TRUE;
       
   635       *atomic = newval;
       
   636     }
       
   637   else
       
   638     result = FALSE;
       
   639   g_mutex_unlock (g_atomic_mutex);
       
   640 
       
   641   return result;
       
   642 }
       
   643 
       
   644 #ifdef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED
       
   645 EXPORT_C gint
       
   646 g_atomic_int_get (volatile gint *atomic)
       
   647 {
       
   648   gint result;
       
   649 
       
   650   g_mutex_lock (g_atomic_mutex);
       
   651   result = *atomic;
       
   652   g_mutex_unlock (g_atomic_mutex);
       
   653 
       
   654   return result;
       
   655 }
       
   656 
       
   657 EXPORT_C void
       
   658 g_atomic_int_set (volatile gint *atomic,
       
   659                   gint           newval)
       
   660 {
       
   661   g_mutex_lock (g_atomic_mutex);
       
   662   *atomic = newval;
       
   663   g_mutex_unlock (g_atomic_mutex);
       
   664 }
       
   665 
       
   666 EXPORT_C gpointer
       
   667 g_atomic_pointer_get (volatile gpointer *atomic)
       
   668 {
       
   669   gpointer result;
       
   670 
       
   671   g_mutex_lock (g_atomic_mutex);
       
   672   result = *atomic;
       
   673   g_mutex_unlock (g_atomic_mutex);
       
   674 
       
   675   return result;
       
   676 }
       
   677 
       
   678 EXPORT_C void
       
   679 g_atomic_pointer_set (volatile gpointer *atomic,
       
   680                       gpointer           newval)
       
   681 {
       
   682   g_mutex_lock (g_atomic_mutex);
       
   683   *atomic = newval;
       
   684   g_mutex_unlock (g_atomic_mutex);
       
   685 }
       
   686 #endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */   
       
   687 #elif defined (G_ATOMIC_OP_MEMORY_BARRIER_NEEDED)
       
   688 EXPORT_C gint
       
   689 g_atomic_int_get (volatile gint *atomic)
       
   690 {
       
   691   G_ATOMIC_MEMORY_BARRIER;
       
   692   return *atomic;
       
   693 }
       
   694 
       
   695 EXPORT_C void
       
   696 g_atomic_int_set (volatile gint *atomic,
       
   697                   gint           newval)
       
   698 {
       
   699   *atomic = newval;
       
   700   G_ATOMIC_MEMORY_BARRIER; 
       
   701 }
       
   702 
       
   703 EXPORT_C gpointer
       
   704 g_atomic_pointer_get (volatile gpointer *atomic)
       
   705 {
       
   706   G_ATOMIC_MEMORY_BARRIER;
       
   707   return *atomic;
       
   708 }   
       
   709 
       
   710 EXPORT_C gpointer
       
   711 g_atomic_pointer_set (volatile gpointer *atomic,
       
   712                       gpointer           newval)
       
   713 {
       
   714   *atomic = newval;
       
   715   G_ATOMIC_MEMORY_BARRIER; 
       
   716 }
       
   717 #endif /* DEFINE_WITH_MUTEXES || G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
       
   718 
       
   719 #ifdef ATOMIC_INT_CMP_XCHG
       
   720 EXPORT_C gboolean
       
   721 g_atomic_int_compare_and_exchange (volatile gint *atomic,
       
   722 				   gint           oldval,
       
   723 				   gint           newval)
       
   724 {
       
   725   return ATOMIC_INT_CMP_XCHG (atomic, oldval, newval);
       
   726 }
       
   727 
       
   728 EXPORT_C gint
       
   729 g_atomic_int_exchange_and_add (volatile gint *atomic,
       
   730 			       gint           val)
       
   731 {
       
   732   gint result;
       
   733   do
       
   734     result = *atomic;
       
   735   while (!ATOMIC_INT_CMP_XCHG (atomic, result, result + val));
       
   736 
       
   737   return result;
       
   738 }
       
   739  
       
   740 EXPORT_C void
       
   741 g_atomic_int_add (volatile gint *atomic,
       
   742 		  gint           val)
       
   743 {
       
   744   gint result;
       
   745   do
       
   746     result = *atomic;
       
   747   while (!ATOMIC_INT_CMP_XCHG (atomic, result, result + val));
       
   748 }
       
   749 #endif /* ATOMIC_INT_CMP_XCHG */
       
   750 
       
   751 void 
       
   752 _g_atomic_thread_init (void)
       
   753 {
       
   754 #ifdef DEFINE_WITH_MUTEXES
       
   755   g_atomic_mutex = g_mutex_new ();
       
   756 #endif /* DEFINE_WITH_MUTEXES */
       
   757 }
       
   758 
       
   759 #ifndef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED
       
   760 EXPORT_C gint
       
   761 (g_atomic_int_get) (volatile gint *atomic)
       
   762 {
       
   763   return g_atomic_int_get (atomic);
       
   764 }
       
   765 
       
   766 EXPORT_C void
       
   767 (g_atomic_int_set) (volatile gint *atomic,
       
   768 		    gint           newval)
       
   769 {
       
   770   g_atomic_int_set (atomic, newval);
       
   771 }
       
   772 
       
   773 EXPORT_C gpointer
       
   774 (g_atomic_pointer_get) (volatile gpointer *atomic)
       
   775 {
       
   776   return g_atomic_pointer_get (atomic);
       
   777 }
       
   778 
       
   779 EXPORT_C void
       
   780 (g_atomic_pointer_set) (volatile gpointer *atomic,
       
   781 			gpointer           newval)
       
   782 {
       
   783   g_atomic_pointer_set (atomic, newval);
       
   784 }
       
   785 #endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
       
   786 
       
   787 #define __G_ATOMIC_C__
       
   788 #include "galiasdef.c"