atomic.h 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. The GNU C Library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. The GNU C Library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with the GNU C Library; if not, write to the Free
  13. Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  14. 02111-1307 USA. */
  15. #include <stdint.h>
  16. #include <sysdep.h>
  17. typedef int8_t atomic8_t;
  18. typedef uint8_t uatomic8_t;
  19. typedef int_fast8_t atomic_fast8_t;
  20. typedef uint_fast8_t uatomic_fast8_t;
  21. typedef int32_t atomic32_t;
  22. typedef uint32_t uatomic32_t;
  23. typedef int_fast32_t atomic_fast32_t;
  24. typedef uint_fast32_t uatomic_fast32_t;
  25. typedef intptr_t atomicptr_t;
  26. typedef uintptr_t uatomicptr_t;
  27. typedef intmax_t atomic_max_t;
  28. typedef uintmax_t uatomic_max_t;
  29. void __arm_link_error (void);
  30. #ifdef __thumb__
  31. /* Note that to allow efficient implementation the arguemtns are reversed
  32. relative to atomic_exchange_acq. */
  33. int __thumb_swpb (int newvalue, void *mem)
  34. attribute_hidden;
  35. unsigned int __thumb_swp (unsigned int newvalue, void *mem)
  36. attribute_hidden;
  37. unsigned int __thumb_cmpxchg (unsigned int oldval, unsigned int newval, void *mem)
  38. attribute_hidden;
  39. #define atomic_exchange_acq(mem, newvalue) \
  40. ({ __typeof (*mem) result; \
  41. if (sizeof (*mem) == 1) \
  42. result = __thumb_swpb (newvalue, mem); \
  43. else if (sizeof (*mem) == 4) \
  44. result = __thumb_swp (newvalue, mem); \
  45. else \
  46. { \
  47. result = 0; \
  48. abort (); \
  49. } \
  50. result; })
  51. #define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \
  52. ({ __arm_link_error (); oldval; })
  53. #define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \
  54. ({ __arm_link_error (); oldval; })
  55. #define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \
  56. ((__typeof (oldval)) __thumb_cmpxchg (oldval, newval, mem))
  57. #define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
  58. ({ __arm_link_error (); oldval; })
  59. #else
  60. /* ARM mode. */
  61. #define atomic_exchange_acq(mem, newvalue) \
  62. ({ __typeof (*mem) _xchg_result; \
  63. if (sizeof (*mem) == 1) \
  64. __asm__ __volatile__ ("swpb %0, %1, [%2]" \
  65. : "=&r,&r" (_xchg_result) \
  66. : "r,0" (newvalue), "r,r" (mem) : "memory"); \
  67. else if (sizeof (*mem) == 4) \
  68. __asm__ __volatile__ ("swp %0, %1, [%2]" \
  69. : "=&r,&r" (_xchg_result) \
  70. : "r,0" (newvalue), "r,r" (mem) : "memory"); \
  71. else \
  72. { \
  73. _xchg_result = 0; \
  74. abort (); \
  75. } \
  76. _xchg_result; })
  77. /* Atomic compare and exchange. This sequence relies on the kernel to
  78. provide a compare and exchange operation which is atomic on the
  79. current architecture, either via cleverness on pre-ARMv6 or via
  80. ldrex / strex on ARMv6. */
  81. #define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \
  82. ({ __arm_link_error (); oldval; })
  83. #define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \
  84. ({ __arm_link_error (); oldval; })
  85. /* It doesn't matter what register is used for a_oldval2, but we must
  86. specify one to work around GCC PR rtl-optimization/21223. Otherwise
  87. it may cause a_oldval or a_tmp to be moved to a different register. */
  88. #define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \
  89. ({ register __typeof (oldval) a_oldval asm ("r0"); \
  90. register __typeof (oldval) a_newval asm ("r1") = (newval); \
  91. register __typeof (mem) a_ptr asm ("r2") = (mem); \
  92. register __typeof (oldval) a_tmp asm ("r3"); \
  93. register __typeof (oldval) a_oldval2 asm ("r4") = (oldval); \
  94. __asm__ __volatile__ \
  95. ("0:\tldr\t%1,[%3]\n\t" \
  96. "cmp\t%1, %4\n\t" \
  97. "bne\t1f\n\t" \
  98. "mov\t%0, %4\n\t" \
  99. "mov\t%1, #0xffff0fff\n\t" \
  100. "mov\tlr, pc\n\t" \
  101. "add\tpc, %1, #(0xffff0fc0 - 0xffff0fff)\n\t" \
  102. "bcc\t0b\n\t" \
  103. "mov\t%1, %4\n\t" \
  104. "1:" \
  105. : "=&r" (a_oldval), "=&r" (a_tmp) \
  106. : "r" (a_newval), "r" (a_ptr), "r" (a_oldval2) \
  107. : "ip", "lr", "cc", "memory"); \
  108. a_tmp; })
  109. #define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
  110. ({ __arm_link_error (); oldval; })
  111. #endif /* __thumb__ */