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 * Copyright (C) 2007 Nokia Corporation 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#if defined (G_ATOMIC_ARM) 27#include <sched.h> 28#endif 29 30#include "glib.h" 31#include "gthreadprivate.h" 32#include "galias.h" 33 34#if defined (__GNUC__) 35# if defined (G_ATOMIC_I486) 36/* Adapted from CVS version 1.10 of glibc's sysdeps/i386/i486/bits/atomic.h 37 */ 38gint 39g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 40 gint val) 41{ 42 gint result; 43 44 __asm__ __volatile__ ("lock; xaddl %0,%1" 45 : "=r" (result), "=m" (*atomic) 46 : "0" (val), "m" (*atomic)); 47 return result; 48} 49 50void 51g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 52 gint val) 53{ 54 __asm__ __volatile__ ("lock; addl %1,%0" 55 : "=m" (*atomic) 56 : "ir" (val), "m" (*atomic)); 57} 58 59gboolean 60g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, 61 gint oldval, 62 gint newval) 63{ 64 gint result; 65 66 __asm__ __volatile__ ("lock; cmpxchgl %2, %1" 67 : "=a" (result), "=m" (*atomic) 68 : "r" (newval), "m" (*atomic), "0" (oldval)); 69 70 return result == oldval; 71} 72 73/* The same code as above, as on i386 gpointer is 32 bit as well. 74 * Duplicating the code here seems more natural than casting the 75 * arguments and calling the former function */ 76 77gboolean 78g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 79 gpointer oldval, 80 gpointer newval) 81{ 82 gpointer result; 83 84 __asm__ __volatile__ ("lock; cmpxchgl %2, %1" 85 : "=a" (result), "=m" (*atomic) 86 : "r" (newval), "m" (*atomic), "0" (oldval)); 87 88 return result == oldval; 89} 90 91# elif defined (G_ATOMIC_SPARCV9) 92/* Adapted from CVS version 1.3 of glibc's sysdeps/sparc/sparc64/bits/atomic.h 93 */ 94# define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval) \ 95 ({ \ 96 gint __result; \ 97 __asm__ __volatile__ ("cas [%4], %2, %0" \ 98 : "=r" (__result), "=m" (*(atomic)) \ 99 : "r" (oldval), "m" (*(atomic)), "r" (atomic),\ 100 "0" (newval)); \ 101 __result == oldval; \ 102 }) 103 104# if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */ 105gboolean 106g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 107 gpointer oldval, 108 gpointer newval) 109{ 110 gpointer result; 111 __asm__ __volatile__ ("cas [%4], %2, %0" 112 : "=r" (result), "=m" (*atomic) 113 : "r" (oldval), "m" (*atomic), "r" (atomic), 114 "0" (newval)); 115 return result == oldval; 116} 117# elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */ 118gboolean 119g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 120 gpointer oldval, 121 gpointer newval) 122{ 123 gpointer result; 124 gpointer *a = atomic; 125 __asm__ __volatile__ ("casx [%4], %2, %0" 126 : "=r" (result), "=m" (*a) 127 : "r" (oldval), "m" (*a), "r" (a), 128 "0" (newval)); 129 return result == oldval; 130} 131# else /* What's that */ 132# error "Your system has an unsupported pointer size" 133# endif /* GLIB_SIZEOF_VOID_P */ 134# define G_ATOMIC_MEMORY_BARRIER \ 135 __asm__ __volatile__ ("membar #LoadLoad | #LoadStore" \ 136 " | #StoreLoad | #StoreStore" : : : "memory") 137 138# elif defined (G_ATOMIC_ALPHA) 139/* Adapted from CVS version 1.3 of glibc's sysdeps/alpha/bits/atomic.h 140 */ 141# define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval) \ 142 ({ \ 143 gint __result; \ 144 gint __prev; \ 145 __asm__ __volatile__ ( \ 146 " mb\n" \ 147 "1: ldl_l %0,%2\n" \ 148 " cmpeq %0,%3,%1\n" \ 149 " beq %1,2f\n" \ 150 " mov %4,%1\n" \ 151 " stl_c %1,%2\n" \ 152 " beq %1,1b\n" \ 153 " mb\n" \ 154 "2:" \ 155 : "=&r" (__prev), \ 156 "=&r" (__result) \ 157 : "m" (*(atomic)), \ 158 "Ir" (oldval), \ 159 "Ir" (newval) \ 160 : "memory"); \ 161 __result != 0; \ 162 }) 163# if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */ 164gboolean 165g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 166 gpointer oldval, 167 gpointer newval) 168{ 169 gint result; 170 gpointer prev; 171 __asm__ __volatile__ ( 172 " mb\n" 173 "1: ldl_l %0,%2\n" 174 " cmpeq %0,%3,%1\n" 175 " beq %1,2f\n" 176 " mov %4,%1\n" 177 " stl_c %1,%2\n" 178 " beq %1,1b\n" 179 " mb\n" 180 "2:" 181 : "=&r" (prev), 182 "=&r" (result) 183 : "m" (*atomic), 184 "Ir" (oldval), 185 "Ir" (newval) 186 : "memory"); 187 return result != 0; 188} 189# elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */ 190gboolean 191g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 192 gpointer oldval, 193 gpointer newval) 194{ 195 gint result; 196 gpointer prev; 197 __asm__ __volatile__ ( 198 " mb\n" 199 "1: ldq_l %0,%2\n" 200 " cmpeq %0,%3,%1\n" 201 " beq %1,2f\n" 202 " mov %4,%1\n" 203 " stq_c %1,%2\n" 204 " beq %1,1b\n" 205 " mb\n" 206 "2:" 207 : "=&r" (prev), 208 "=&r" (result) 209 : "m" (*atomic), 210 "Ir" (oldval), 211 "Ir" (newval) 212 : "memory"); 213 return result != 0; 214} 215# else /* What's that */ 216# error "Your system has an unsupported pointer size" 217# endif /* GLIB_SIZEOF_VOID_P */ 218# define G_ATOMIC_MEMORY_BARRIER __asm__ ("mb" : : : "memory") 219# elif defined (G_ATOMIC_X86_64) 220/* Adapted from CVS version 1.9 of glibc's sysdeps/x86_64/bits/atomic.h 221 */ 222gint 223g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 224 gint val) 225{ 226 gint result; 227 228 __asm__ __volatile__ ("lock; xaddl %0,%1" 229 : "=r" (result), "=m" (*atomic) 230 : "0" (val), "m" (*atomic)); 231 return result; 232} 233 234void 235g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 236 gint val) 237{ 238 __asm__ __volatile__ ("lock; addl %1,%0" 239 : "=m" (*atomic) 240 : "ir" (val), "m" (*atomic)); 241} 242 243gboolean 244g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, 245 gint oldval, 246 gint newval) 247{ 248 gint result; 249 250 __asm__ __volatile__ ("lock; cmpxchgl %2, %1" 251 : "=a" (result), "=m" (*atomic) 252 : "r" (newval), "m" (*atomic), "0" (oldval)); 253 254 return result == oldval; 255} 256 257gboolean 258g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 259 gpointer oldval, 260 gpointer newval) 261{ 262 gpointer result; 263 264 __asm__ __volatile__ ("lock; cmpxchgq %q2, %1" 265 : "=a" (result), "=m" (*atomic) 266 : "r" (newval), "m" (*atomic), "0" (oldval)); 267 268 return result == oldval; 269} 270 271# elif defined (G_ATOMIC_POWERPC) 272/* Adapted from CVS version 1.16 of glibc's sysdeps/powerpc/bits/atomic.h 273 * and CVS version 1.4 of glibc's sysdeps/powerpc/powerpc32/bits/atomic.h 274 * and CVS version 1.7 of glibc's sysdeps/powerpc/powerpc64/bits/atomic.h 275 */ 276# ifdef __OPTIMIZE__ 277/* Non-optimizing compile bails on the following two asm statements 278 * for reasons unknown to the author */ 279gint 280g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 281 gint val) 282{ 283 gint result, temp; 284#if ASM_NUMERIC_LABELS 285 __asm__ __volatile__ ("1: lwarx %0,0,%3\n" 286 " add %1,%0,%4\n" 287 " stwcx. %1,0,%3\n" 288 " bne- 1b" 289 : "=&b" (result), "=&r" (temp), "=m" (*atomic) 290 : "b" (atomic), "r" (val), "m" (*atomic) 291 : "cr0", "memory"); 292#else 293 __asm__ __volatile__ (".Lieaa%=: lwarx %0,0,%3\n" 294 " add %1,%0,%4\n" 295 " stwcx. %1,0,%3\n" 296 " bne- .Lieaa%=" 297 : "=&b" (result), "=&r" (temp), "=m" (*atomic) 298 : "b" (atomic), "r" (val), "m" (*atomic) 299 : "cr0", "memory"); 300#endif 301 return result; 302} 303 304/* The same as above, to save a function call repeated here */ 305void 306g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 307 gint val) 308{ 309 gint result, temp; 310#if ASM_NUMERIC_LABELS 311 __asm__ __volatile__ ("1: lwarx %0,0,%3\n" 312 " add %1,%0,%4\n" 313 " stwcx. %1,0,%3\n" 314 " bne- 1b" 315 : "=&b" (result), "=&r" (temp), "=m" (*atomic) 316 : "b" (atomic), "r" (val), "m" (*atomic) 317 : "cr0", "memory"); 318#else 319 __asm__ __volatile__ (".Lia%=: lwarx %0,0,%3\n" 320 " add %1,%0,%4\n" 321 " stwcx. %1,0,%3\n" 322 " bne- .Lia%=" 323 : "=&b" (result), "=&r" (temp), "=m" (*atomic) 324 : "b" (atomic), "r" (val), "m" (*atomic) 325 : "cr0", "memory"); 326#endif 327} 328# else /* !__OPTIMIZE__ */ 329gint 330g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 331 gint val) 332{ 333 gint result; 334 do 335 result = *atomic; 336 while (!g_atomic_int_compare_and_exchange (atomic, result, result + val)); 337 338 return result; 339} 340 341void 342g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 343 gint val) 344{ 345 gint result; 346 do 347 result = *atomic; 348 while (!g_atomic_int_compare_and_exchange (atomic, result, result + val)); 349} 350# endif /* !__OPTIMIZE__ */ 351 352# if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */ 353gboolean 354g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, 355 gint oldval, 356 gint newval) 357{ 358 gint result; 359#if ASM_NUMERIC_LABELS 360 __asm__ __volatile__ ("sync\n" 361 "1: lwarx %0,0,%1\n" 362 " subf. %0,%2,%0\n" 363 " bne 2f\n" 364 " stwcx. %3,0,%1\n" 365 " bne- 1b\n" 366 "2: isync" 367 : "=&r" (result) 368 : "b" (atomic), "r" (oldval), "r" (newval) 369 : "cr0", "memory"); 370#else 371 __asm__ __volatile__ ("sync\n" 372 ".L1icae%=: lwarx %0,0,%1\n" 373 " subf. %0,%2,%0\n" 374 " bne .L2icae%=\n" 375 " stwcx. %3,0,%1\n" 376 " bne- .L1icae%=\n" 377 ".L2icae%=: isync" 378 : "=&r" (result) 379 : "b" (atomic), "r" (oldval), "r" (newval) 380 : "cr0", "memory"); 381#endif 382 return result == 0; 383} 384 385gboolean 386g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 387 gpointer oldval, 388 gpointer newval) 389{ 390 gpointer result; 391#if ASM_NUMERIC_LABELS 392 __asm__ __volatile__ ("sync\n" 393 "1: lwarx %0,0,%1\n" 394 " subf. %0,%2,%0\n" 395 " bne 2f\n" 396 " stwcx. %3,0,%1\n" 397 " bne- 1b\n" 398 "2: isync" 399 : "=&r" (result) 400 : "b" (atomic), "r" (oldval), "r" (newval) 401 : "cr0", "memory"); 402#else 403 __asm__ __volatile__ ("sync\n" 404 ".L1pcae%=: lwarx %0,0,%1\n" 405 " subf. %0,%2,%0\n" 406 " bne .L2pcae%=\n" 407 " stwcx. %3,0,%1\n" 408 " bne- .L1pcae%=\n" 409 ".L2pcae%=: isync" 410 : "=&r" (result) 411 : "b" (atomic), "r" (oldval), "r" (newval) 412 : "cr0", "memory"); 413#endif 414 return result == 0; 415} 416# elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */ 417gboolean 418g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, 419 gint oldval, 420 gint newval) 421{ 422 gpointer result; 423#if ASM_NUMERIC_LABELS 424 __asm__ __volatile__ ("sync\n" 425 "1: lwarx %0,0,%1\n" 426 " extsw %0,%0\n" 427 " subf. %0,%2,%0\n" 428 " bne 2f\n" 429 " stwcx. %3,0,%1\n" 430 " bne- 1b\n" 431 "2: isync" 432 : "=&r" (result) 433 : "b" (atomic), "r" (oldval), "r" (newval) 434 : "cr0", "memory"); 435#else 436 __asm__ __volatile__ ("sync\n" 437 ".L1icae%=: lwarx %0,0,%1\n" 438 " extsw %0,%0\n" 439 " subf. %0,%2,%0\n" 440 " bne .L2icae%=\n" 441 " stwcx. %3,0,%1\n" 442 " bne- .L1icae%=\n" 443 ".L2icae%=: isync" 444 : "=&r" (result) 445 : "b" (atomic), "r" (oldval), "r" (newval) 446 : "cr0", "memory"); 447#endif 448 return result == 0; 449} 450 451gboolean 452g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 453 gpointer oldval, 454 gpointer newval) 455{ 456 gpointer result; 457#if ASM_NUMERIC_LABELS 458 __asm__ __volatile__ ("sync\n" 459 "1: ldarx %0,0,%1\n" 460 " subf. %0,%2,%0\n" 461 " bne 2f\n" 462 " stdcx. %3,0,%1\n" 463 " bne- 1b\n" 464 "2: isync" 465 : "=&r" (result) 466 : "b" (atomic), "r" (oldval), "r" (newval) 467 : "cr0", "memory"); 468#else 469 __asm__ __volatile__ ("sync\n" 470 ".L1pcae%=: ldarx %0,0,%1\n" 471 " subf. %0,%2,%0\n" 472 " bne .L2pcae%=\n" 473 " stdcx. %3,0,%1\n" 474 " bne- .L1pcae%=\n" 475 ".L2pcae%=: isync" 476 : "=&r" (result) 477 : "b" (atomic), "r" (oldval), "r" (newval) 478 : "cr0", "memory"); 479#endif 480 return result == 0; 481} 482# else /* What's that */ 483# error "Your system has an unsupported pointer size" 484# endif /* GLIB_SIZEOF_VOID_P */ 485 486# define G_ATOMIC_MEMORY_BARRIER __asm__ ("sync" : : : "memory") 487 488# elif defined (G_ATOMIC_IA64) 489/* Adapted from CVS version 1.8 of glibc's sysdeps/ia64/bits/atomic.h 490 */ 491gint 492g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 493 gint val) 494{ 495 return __sync_fetch_and_add (atomic, val); 496} 497 498void 499g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 500 gint val) 501{ 502 __sync_fetch_and_add (atomic, val); 503} 504 505gboolean 506g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, 507 gint oldval, 508 gint newval) 509{ 510 return __sync_bool_compare_and_swap (atomic, oldval, newval); 511} 512 513gboolean 514g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 515 gpointer oldval, 516 gpointer newval) 517{ 518 return __sync_bool_compare_and_swap ((long *)atomic, 519 (long)oldval, (long)newval); 520} 521 522# define G_ATOMIC_MEMORY_BARRIER __sync_synchronize () 523# elif defined (G_ATOMIC_S390) 524/* Adapted from glibc's sysdeps/s390/bits/atomic.h 525 */ 526# define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval) \ 527 ({ \ 528 gint __result = oldval; \ 529 __asm__ __volatile__ ("cs %0, %2, %1" \ 530 : "+d" (__result), "=Q" (*(atomic)) \ 531 : "d" (newval), "m" (*(atomic)) : "cc" ); \ 532 __result == oldval; \ 533 }) 534 535# if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */ 536gboolean 537g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 538 gpointer oldval, 539 gpointer newval) 540{ 541 gpointer result = oldval; 542 __asm__ __volatile__ ("cs %0, %2, %1" 543 : "+d" (result), "=Q" (*(atomic)) 544 : "d" (newval), "m" (*(atomic)) : "cc" ); 545 return result == oldval; 546} 547# elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */ 548gboolean 549g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 550 gpointer oldval, 551 gpointer newval) 552{ 553 gpointer result = oldval; 554 gpointer *a = atomic; 555 __asm__ __volatile__ ("csg %0, %2, %1" 556 : "+d" (result), "=Q" (*a) 557 : "d" ((long)(newval)), "m" (*a) : "cc" ); 558 return result == oldval; 559} 560# else /* What's that */ 561# error "Your system has an unsupported pointer size" 562# endif /* GLIB_SIZEOF_VOID_P */ 563# elif defined (G_ATOMIC_ARM) 564static volatile int atomic_spin = 0; 565 566static int atomic_spin_trylock (void) 567{ 568 int result; 569 570 asm volatile ( 571 "swp %0, %1, [%2]\n" 572 : "=&r,&r" (result) 573 : "r,0" (1), "r,r" (&atomic_spin) 574 : "memory"); 575 if (result == 0) 576 return 0; 577 else 578 return -1; 579} 580 581static void atomic_spin_lock (void) 582{ 583 while (atomic_spin_trylock()) 584 sched_yield(); 585} 586 587static void atomic_spin_unlock (void) 588{ 589 atomic_spin = 0; 590} 591 592gint 593g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 594 gint val) 595{ 596 gint result; 597 598 atomic_spin_lock(); 599 result = *atomic; 600 *atomic += val; 601 atomic_spin_unlock(); 602 603 return result; 604} 605 606void 607g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 608 gint val) 609{ 610 atomic_spin_lock(); 611 *atomic += val; 612 atomic_spin_unlock(); 613} 614 615gboolean 616g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, 617 gint oldval, 618 gint newval) 619{ 620 gboolean result; 621 622 atomic_spin_lock(); 623 if (*atomic == oldval) 624 { 625 result = TRUE; 626 *atomic = newval; 627 } 628 else 629 result = FALSE; 630 atomic_spin_unlock(); 631 632 return result; 633} 634 635gboolean 636g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 637 gpointer oldval, 638 gpointer newval) 639{ 640 gboolean result; 641 642 atomic_spin_lock(); 643 if (*atomic == oldval) 644 { 645 result = TRUE; 646 *atomic = newval; 647 } 648 else 649 result = FALSE; 650 atomic_spin_unlock(); 651 652 return result; 653} 654# elif defined (G_ATOMIC_CRIS) || defined (G_ATOMIC_CRISV32) 655# ifdef G_ATOMIC_CRIS 656# define CRIS_ATOMIC_INT_CMP_XCHG(atomic, oldval, newval) \ 657 ({ \ 658 gboolean __result; \ 659 __asm__ __volatile__ ("\n" \ 660 "0:\tclearf\n\t" \ 661 "cmp.d [%[Atomic]], %[OldVal]\n\t" \ 662 "bne 1f\n\t" \ 663 "ax\n\t" \ 664 "move.d %[NewVal], [%[Atomic]]\n\t" \ 665 "bwf 0b\n" \ 666 "1:\tseq %[Result]" \ 667 : [Result] "=&r" (__result), \ 668 "=m" (*(atomic)) \ 669 : [Atomic] "r" (atomic), \ 670 [OldVal] "r" (oldval), \ 671 [NewVal] "r" (newval), \ 672 "g" (*(gpointer*) (atomic)) \ 673 : "memory"); \ 674 __result; \ 675 }) 676# else 677# define CRIS_ATOMIC_INT_CMP_XCHG(atomic, oldval, newval) \ 678 ({ \ 679 gboolean __result; \ 680 __asm__ __volatile__ ("\n" \ 681 "0:\tclearf p\n\t" \ 682 "cmp.d [%[Atomic]], %[OldVal]\n\t" \ 683 "bne 1f\n\t" \ 684 "ax\n\t" \ 685 "move.d %[NewVal], [%[Atomic]]\n\t" \ 686 "bcs 0b\n" \ 687 "1:\tseq %[Result]" \ 688 : [Result] "=&r" (__result), \ 689 "=m" (*(atomic)) \ 690 : [Atomic] "r" (atomic), \ 691 [OldVal] "r" (oldval), \ 692 [NewVal] "r" (newval), \ 693 "g" (*(gpointer*) (atomic)) \ 694 : "memory"); \ 695 __result; \ 696 }) 697# endif 698 699#define CRIS_CACHELINE_SIZE 32 700#define CRIS_ATOMIC_BREAKS_CACHELINE(atomic) \ 701 (((gulong)(atomic) & (CRIS_CACHELINE_SIZE - 1)) > (CRIS_CACHELINE_SIZE - sizeof (atomic))) 702 703gint __g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 704 gint val); 705void __g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 706 gint val); 707gboolean __g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, 708 gint oldval, 709 gint newval); 710gboolean __g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 711 gpointer oldval, 712 gpointer newval); 713 714gboolean 715g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 716 gpointer oldval, 717 gpointer newval) 718{ 719 if (G_UNLIKELY (CRIS_ATOMIC_BREAKS_CACHELINE (atomic))) 720 return __g_atomic_pointer_compare_and_exchange (atomic, oldval, newval); 721 722 return CRIS_ATOMIC_INT_CMP_XCHG (atomic, oldval, newval); 723} 724 725gboolean 726g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, 727 gint oldval, 728 gint newval) 729{ 730 if (G_UNLIKELY (CRIS_ATOMIC_BREAKS_CACHELINE (atomic))) 731 return __g_atomic_int_compare_and_exchange (atomic, oldval, newval); 732 733 return CRIS_ATOMIC_INT_CMP_XCHG (atomic, oldval, newval); 734} 735 736gint 737g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 738 gint val) 739{ 740 gint result; 741 742 if (G_UNLIKELY (CRIS_ATOMIC_BREAKS_CACHELINE (atomic))) 743 return __g_atomic_int_exchange_and_add (atomic, val); 744 745 do 746 result = *atomic; 747 while (!CRIS_ATOMIC_INT_CMP_XCHG (atomic, result, result + val)); 748 749 return result; 750} 751 752void 753g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 754 gint val) 755{ 756 gint result; 757 758 if (G_UNLIKELY (CRIS_ATOMIC_BREAKS_CACHELINE (atomic))) 759 return __g_atomic_int_add (atomic, val); 760 761 do 762 result = *atomic; 763 while (!CRIS_ATOMIC_INT_CMP_XCHG (atomic, result, result + val)); 764} 765 766/* We need the atomic mutex for atomic operations where the atomic variable 767 * breaks the 32 byte cache line since the CRIS architecture does not support 768 * atomic operations on such variables. Fortunately this should be rare. 769 */ 770# define DEFINE_WITH_MUTEXES 771# define g_atomic_int_exchange_and_add __g_atomic_int_exchange_and_add 772# define g_atomic_int_add __g_atomic_int_add 773# define g_atomic_int_compare_and_exchange __g_atomic_int_compare_and_exchange 774# define g_atomic_pointer_compare_and_exchange __g_atomic_pointer_compare_and_exchange 775 776# else /* !G_ATOMIC_* */ 777# define DEFINE_WITH_MUTEXES 778# endif /* G_ATOMIC_* */ 779#else /* !__GNUC__ */ 780# ifdef G_PLATFORM_WIN32 781# define DEFINE_WITH_WIN32_INTERLOCKED 782# else 783# define DEFINE_WITH_MUTEXES 784# endif 785#endif /* __GNUC__ */ 786 787#ifdef DEFINE_WITH_WIN32_INTERLOCKED 788# include <windows.h> 789/* Following indicates that InterlockedCompareExchangePointer is 790 * declared in winbase.h (included by windows.h) and needs to be 791 * commented out if not true. It is defined iff WINVER > 0x0400, 792 * which is usually correct but can be wrong if WINVER is set before 793 * windows.h is included. 794 */ 795# if WINVER > 0x0400 796# define HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER 797# endif 798 799gint32 800g_atomic_int_exchange_and_add (volatile gint32 G_GNUC_MAY_ALIAS *atomic, 801 gint32 val) 802{ 803 return InterlockedExchangeAdd (atomic, val); 804} 805 806void 807g_atomic_int_add (volatile gint32 G_GNUC_MAY_ALIAS *atomic, 808 gint32 val) 809{ 810 InterlockedExchangeAdd (atomic, val); 811} 812 813gboolean 814g_atomic_int_compare_and_exchange (volatile gint32 G_GNUC_MAY_ALIAS *atomic, 815 gint32 oldval, 816 gint32 newval) 817{ 818#ifndef HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER 819 return (guint32) InterlockedCompareExchange ((PVOID*)atomic, 820 (PVOID)newval, 821 (PVOID)oldval) == oldval; 822#else 823 return InterlockedCompareExchange (atomic, 824 newval, 825 oldval) == oldval; 826#endif 827} 828 829gboolean 830g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 831 gpointer oldval, 832 gpointer newval) 833{ 834# ifdef HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER 835 return InterlockedCompareExchangePointer (atomic, newval, oldval) == oldval; 836# else 837# if GLIB_SIZEOF_VOID_P != 4 /* no 32-bit system */ 838# error "InterlockedCompareExchangePointer needed" 839# else 840 return InterlockedCompareExchange (atomic, newval, oldval) == oldval; 841# endif 842# endif 843} 844#endif /* DEFINE_WITH_WIN32_INTERLOCKED */ 845 846#ifdef DEFINE_WITH_MUTEXES 847/* We have to use the slow, but safe locking method */ 848static GMutex *g_atomic_mutex; 849 850gint 851g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 852 gint val) 853{ 854 gint result; 855 856 g_mutex_lock (g_atomic_mutex); 857 result = *atomic; 858 *atomic += val; 859 g_mutex_unlock (g_atomic_mutex); 860 861 return result; 862} 863 864 865void 866g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 867 gint val) 868{ 869 g_mutex_lock (g_atomic_mutex); 870 *atomic += val; 871 g_mutex_unlock (g_atomic_mutex); 872} 873 874gboolean 875g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, 876 gint oldval, 877 gint newval) 878{ 879 gboolean result; 880 881 g_mutex_lock (g_atomic_mutex); 882 if (*atomic == oldval) 883 { 884 result = TRUE; 885 *atomic = newval; 886 } 887 else 888 result = FALSE; 889 g_mutex_unlock (g_atomic_mutex); 890 891 return result; 892} 893 894gboolean 895g_atomic_pointer_compare_and_exchange (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 896 gpointer oldval, 897 gpointer newval) 898{ 899 gboolean result; 900 901 g_mutex_lock (g_atomic_mutex); 902 if (*atomic == oldval) 903 { 904 result = TRUE; 905 *atomic = newval; 906 } 907 else 908 result = FALSE; 909 g_mutex_unlock (g_atomic_mutex); 910 911 return result; 912} 913 914#ifdef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED 915gint 916(g_atomic_int_get) (volatile gint G_GNUC_MAY_ALIAS *atomic) 917{ 918 gint result; 919 920 g_mutex_lock (g_atomic_mutex); 921 result = *atomic; 922 g_mutex_unlock (g_atomic_mutex); 923 924 return result; 925} 926 927void 928(g_atomic_int_set) (volatile gint G_GNUC_MAY_ALIAS *atomic, 929 gint newval) 930{ 931 g_mutex_lock (g_atomic_mutex); 932 *atomic = newval; 933 g_mutex_unlock (g_atomic_mutex); 934} 935 936gpointer 937(g_atomic_pointer_get) (volatile gpointer G_GNUC_MAY_ALIAS *atomic) 938{ 939 gpointer result; 940 941 g_mutex_lock (g_atomic_mutex); 942 result = *atomic; 943 g_mutex_unlock (g_atomic_mutex); 944 945 return result; 946} 947 948void 949(g_atomic_pointer_set) (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 950 gpointer newval) 951{ 952 g_mutex_lock (g_atomic_mutex); 953 *atomic = newval; 954 g_mutex_unlock (g_atomic_mutex); 955} 956#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */ 957#elif defined (G_ATOMIC_OP_MEMORY_BARRIER_NEEDED) 958gint 959(g_atomic_int_get) (volatile gint G_GNUC_MAY_ALIAS *atomic) 960{ 961 G_ATOMIC_MEMORY_BARRIER; 962 return *atomic; 963} 964 965void 966(g_atomic_int_set) (volatile gint G_GNUC_MAY_ALIAS *atomic, 967 gint newval) 968{ 969 *atomic = newval; 970 G_ATOMIC_MEMORY_BARRIER; 971} 972 973gpointer 974(g_atomic_pointer_get) (volatile gpointer G_GNUC_MAY_ALIAS *atomic) 975{ 976 G_ATOMIC_MEMORY_BARRIER; 977 return *atomic; 978} 979 980void 981(g_atomic_pointer_set) (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 982 gpointer newval) 983{ 984 *atomic = newval; 985 G_ATOMIC_MEMORY_BARRIER; 986} 987#endif /* DEFINE_WITH_MUTEXES || G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */ 988 989#ifdef ATOMIC_INT_CMP_XCHG 990gboolean 991g_atomic_int_compare_and_exchange (volatile gint G_GNUC_MAY_ALIAS *atomic, 992 gint oldval, 993 gint newval) 994{ 995 return ATOMIC_INT_CMP_XCHG (atomic, oldval, newval); 996} 997 998gint 999g_atomic_int_exchange_and_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 1000 gint val) 1001{ 1002 gint result; 1003 do 1004 result = *atomic; 1005 while (!ATOMIC_INT_CMP_XCHG (atomic, result, result + val)); 1006 1007 return result; 1008} 1009 1010void 1011g_atomic_int_add (volatile gint G_GNUC_MAY_ALIAS *atomic, 1012 gint val) 1013{ 1014 gint result; 1015 do 1016 result = *atomic; 1017 while (!ATOMIC_INT_CMP_XCHG (atomic, result, result + val)); 1018} 1019#endif /* ATOMIC_INT_CMP_XCHG */ 1020 1021void 1022_g_atomic_thread_init (void) 1023{ 1024#ifdef DEFINE_WITH_MUTEXES 1025 g_atomic_mutex = g_mutex_new (); 1026#endif /* DEFINE_WITH_MUTEXES */ 1027} 1028 1029#ifndef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED 1030gint 1031(g_atomic_int_get) (volatile gint G_GNUC_MAY_ALIAS *atomic) 1032{ 1033 return g_atomic_int_get (atomic); 1034} 1035 1036void 1037(g_atomic_int_set) (volatile gint G_GNUC_MAY_ALIAS *atomic, 1038 gint newval) 1039{ 1040 g_atomic_int_set (atomic, newval); 1041} 1042 1043gpointer 1044(g_atomic_pointer_get) (volatile gpointer G_GNUC_MAY_ALIAS *atomic) 1045{ 1046 return g_atomic_pointer_get (atomic); 1047} 1048 1049void 1050(g_atomic_pointer_set) (volatile gpointer G_GNUC_MAY_ALIAS *atomic, 1051 gpointer newval) 1052{ 1053 g_atomic_pointer_set (atomic, newval); 1054} 1055#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */ 1056 1057#define __G_ATOMIC_C__ 1058#include "galiasdef.c" 1059