atomic.h 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. /* Atomic operations. MicroBlaze version.
  2. Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  3. MicroBlaze (ISA v8+) has 32-bit load/store-exclusive instructions
  4. (lwx/swx). We implement the compare-and-exchange primitive directly
  5. with them rather than via the __sync_* builtins: gcc's MicroBlaze
  6. __sync code generation is broken (it emits the lwx/swx pair without
  7. the compare-branch and without retrying on a failed swx), so the
  8. builtin compare-and-exchange neither swaps nor returns the right
  9. value. A hand-written lwx/swx loop works correctly.
  10. Without this file MicroBlaze fell back to the generic non-atomic
  11. bits/atomic.h, whose "atomic" compare-and-exchange is a plain
  12. read-compare-write. Under sustained contention a preemption between
  13. the read and the write corrupts NPTL's lock and condition-variable
  14. state, which showed up as lost wakeups (tst-cond16/tst-cond17 hung
  15. until the test timeout).
  16. Only 32-bit objects are supported (lwx/swx are word operations); the
  17. NPTL and include/atomic.h users only ever operate on int- and
  18. pointer-sized objects, and the higher-level operations are derived
  19. from the compare-and-exchange primitive below. */
  20. #ifndef _MICROBLAZE_BITS_ATOMIC_H
  21. #define _MICROBLAZE_BITS_ATOMIC_H 1
  22. #include <stdint.h>
  23. typedef int8_t atomic8_t;
  24. typedef uint8_t uatomic8_t;
  25. typedef int_fast8_t atomic_fast8_t;
  26. typedef uint_fast8_t uatomic_fast8_t;
  27. typedef int16_t atomic16_t;
  28. typedef uint16_t uatomic16_t;
  29. typedef int_fast16_t atomic_fast16_t;
  30. typedef uint_fast16_t uatomic_fast16_t;
  31. typedef int32_t atomic32_t;
  32. typedef uint32_t uatomic32_t;
  33. typedef int_fast32_t atomic_fast32_t;
  34. typedef uint_fast32_t uatomic_fast32_t;
  35. typedef int64_t atomic64_t;
  36. typedef uint64_t uatomic64_t;
  37. typedef int_fast64_t atomic_fast64_t;
  38. typedef uint_fast64_t uatomic_fast64_t;
  39. typedef intptr_t atomicptr_t;
  40. typedef uintptr_t uatomicptr_t;
  41. typedef intmax_t atomic_max_t;
  42. typedef uintmax_t uatomic_max_t;
  43. /* UP MicroBlaze; lwx/swx provide the ordering for the atomic itself, a
  44. plain compiler barrier is enough around it. */
  45. #define atomic_full_barrier() __asm__ __volatile__ ("" ::: "memory")
  46. #define atomic_read_barrier() atomic_full_barrier ()
  47. #define atomic_write_barrier() atomic_full_barrier ()
  48. /* Store NEWVAL in *MEM if *MEM equals OLDVAL; return the old *MEM value.
  49. lwx loads exclusive (arming the reservation), swx stores exclusive and
  50. sets MSR[C]=1 if the reservation was lost, in which case we retry. */
  51. #define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
  52. ({ __typeof (*(mem)) __acev_ret; \
  53. __typeof (*(mem)) __acev_nv = (newval); \
  54. __typeof (*(mem)) __acev_ov = (oldval); \
  55. int __acev_fail; \
  56. __asm__ __volatile__ ( \
  57. "1: lwx %0, %2, r0\n\t" \
  58. " cmpu %1, %0, %3\n\t" \
  59. " bnei %1, 2f\n\t" \
  60. " swx %4, %2, r0\n\t" \
  61. " addic %1, r0, 0\n\t" \
  62. " bnei %1, 1b\n\t" \
  63. "2:" \
  64. : "=&r" (__acev_ret), "=&r" (__acev_fail) \
  65. : "r" (mem), "r" (__acev_ov), "r" (__acev_nv) \
  66. : "cc", "memory"); \
  67. __acev_ret; })
  68. #define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
  69. ({ __typeof (*(mem)) __aceb_ov = (oldval); \
  70. atomic_compare_and_exchange_val_acq ((mem), (newval), __aceb_ov) \
  71. != __aceb_ov; })
  72. /* atomic_exchange_acq and the higher-level operations are derived from
  73. the compare-and-exchange primitive by include/atomic.h. */
  74. #endif /* _MICROBLAZE_BITS_ATOMIC_H */