AtomicQueue.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #pragma once
  2. #include "UnityPlatformConfigure.h"
  3. #include "ExtendedAtomicTypes.h"
  4. UNITY_PLATFORM_BEGIN_NAMESPACE;
  5. #if defined(ATOMIC_HAS_DCAS)
  6. #define ATOMIC_HAS_QUEUE 2
  7. #elif (defined(__arm64__) || defined(__aarch64__)) && (defined(__clang__) || defined(__GNUC__))
  8. #define ATOMIC_HAS_QUEUE 1
  9. #elif defined(__arm__) && (defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)) && (!UNITY_STV_API) && (defined(__clang__) || defined(__GNUC__) || defined(SN_TARGET_PSP2))
  10. #define ATOMIC_HAS_QUEUE 1
  11. #endif
  12. class AtomicNode
  13. {
  14. friend class AtomicStack;
  15. friend class AtomicQueue;
  16. volatile atomic_word _next;
  17. public:
  18. void* data[3];
  19. AtomicNode *Next() const
  20. {
  21. return (AtomicNode*)_next;
  22. }
  23. AtomicNode *Link(AtomicNode *next);
  24. };
  25. #if defined(ATOMIC_HAS_QUEUE)
  26. // A generic lockfree stack.
  27. // Any thread can Push / Pop nodes to the stack.
  28. // The stack is lockfree and highly optimized. It has different implementations for different architectures.
  29. // On intel / arm it is built with double CAS:
  30. // http://en.wikipedia.org/wiki/Double_compare-and-swap
  31. // On PPC it is built on LL/SC:
  32. // http://en.wikipedia.org/wiki/Load-link/store-conditional
  33. class AtomicStack
  34. {
  35. #if defined(ATOMIC_HAS_DCAS)
  36. volatile atomic_word2 _top;
  37. #else
  38. volatile atomic_word _top;
  39. #endif
  40. public:
  41. AtomicStack();
  42. ~AtomicStack();
  43. int IsEmpty() const;
  44. void Push(AtomicNode *node);
  45. void PushAll(AtomicNode *first, AtomicNode *last);
  46. AtomicNode *Pop();
  47. AtomicNode *PopAll();
  48. };
  49. AtomicStack* CreateAtomicStack();
  50. void DestroyAtomicStack(AtomicStack* s);
  51. // A generic lockfree queue FIFO queue.
  52. // Any thread can Enqueue / Dequeue in paralell.
  53. // When pushing / popping a node there is no guarantee that the pointer to the node is the same (void* data[3])
  54. // We do guarantee that all 3 data pointer are the same after deqeuing.
  55. // The queue is lockfree and highly optimized. It has different implementations for different archectures.
  56. // On intel / arm it is built with double CAS:
  57. // http://en.wikipedia.org/wiki/Double_compare-and-swap
  58. // On PPC it is built on LL/SC:
  59. // http://en.wikipedia.org/wiki/Load-link/store-conditional
  60. class AtomicQueue
  61. {
  62. #if defined(ATOMIC_HAS_DCAS)
  63. volatile atomic_word2 _tail;
  64. #else
  65. volatile atomic_word _tail;
  66. #endif
  67. volatile atomic_word _head;
  68. public:
  69. AtomicQueue();
  70. ~AtomicQueue();
  71. int IsEmpty() const;
  72. void Enqueue(AtomicNode *node);
  73. void EnqueueAll(AtomicNode *first, AtomicNode *last);
  74. AtomicNode *Dequeue();
  75. };
  76. AtomicQueue* CreateAtomicQueue();
  77. void DestroyAtomicQueue(AtomicQueue* s);
  78. #elif IL2CPP_SUPPORT_THREADS
  79. #error Platform is missing atomic queue implementation
  80. #endif
  81. //
  82. // Special concurrent list for JobQueue
  83. // This code is not meant to be general purpose and should not be used outside of the job queue.
  84. class AtomicList
  85. {
  86. #if defined(ATOMIC_HAS_DCAS)
  87. volatile atomic_word2 _top;
  88. #else
  89. volatile atomic_word _top;
  90. volatile atomic_word _ver;
  91. #endif
  92. public:
  93. void Init();
  94. atomic_word Tag();
  95. AtomicNode *Peek();
  96. AtomicNode *Load(atomic_word &tag);
  97. AtomicNode *Clear(AtomicNode *old, atomic_word tag);
  98. bool Add(AtomicNode *first, AtomicNode *last, atomic_word tag);
  99. AtomicNode* Touch(atomic_word tag);
  100. void Reset(AtomicNode *node, atomic_word tag);
  101. static void Relax();
  102. };
  103. UNITY_PLATFORM_END_NAMESPACE;