General Purpose library for Freestanding C++ and POSIX systems
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

103 行
2.0 KiB

  1. #pragma once
  2. #include "gp/system/process_data.hpp"
  3. #include <atomic>
  4. #include <new>
  5. namespace gp {
  6. struct topic_list{
  7. struct node{
  8. alignas(gp_config::limits::hardware_constructive_interference_size) std::atomic_bool is_locked;
  9. gp::process_data* value;
  10. alignas(gp_config::limits::hardware_constructive_interference_size) std::atomic<struct node*> next;
  11. node()
  12. {
  13. is_locked = false;
  14. value = nullptr;
  15. next = nullptr;
  16. }
  17. node(node&& v)
  18. {
  19. v.try_acquire();
  20. is_locked = false;
  21. value = gp::move(v.value);
  22. next = v.next.load();
  23. }
  24. bool try_acquire() noexcept {
  25. bool expected = false;
  26. return !(is_locked.compare_exchange_strong(expected, true));
  27. }
  28. void release() noexcept {
  29. is_locked.store(false);
  30. }
  31. };
  32. using node_ptr = struct node*;
  33. using node_ptr_rep = std::atomic<struct node*>;
  34. topic_list()
  35. : start{nullptr}
  36. , end{nullptr}
  37. {}
  38. node_ptr_rep start;
  39. node_ptr_rep end;
  40. // NODES ARE ACQUIRED ON POP
  41. node_ptr try_pop() {
  42. auto ptr = start.load();
  43. if(!ptr) return nullptr;
  44. if(ptr->try_acquire()) {
  45. auto replace = ptr->next.load();
  46. auto expected = ptr;
  47. if(end.load() == ptr) {
  48. replace = nullptr;
  49. }
  50. if(start.compare_exchange_strong(expected, replace)) {
  51. end.store(nullptr);
  52. return ptr;
  53. } else {
  54. return nullptr;
  55. }
  56. } else {
  57. return nullptr;
  58. }
  59. }
  60. // ONLY PUSH ACQUIRED NODES,
  61. // RELEASE WHEN NO LONGER IN USE
  62. bool try_push(node_ptr node) {
  63. node->next.store(nullptr);
  64. auto ed = end.load();
  65. if(ed) {
  66. if(ed->try_acquire()) {
  67. auto old_ed = ed;
  68. node->next.store(ed);
  69. if(end.compare_exchange_strong(ed, node)) {
  70. node->release();
  71. old_ed->release();
  72. return true;
  73. } else {
  74. node->release();
  75. old_ed->release();
  76. return false;
  77. }
  78. } else return false;
  79. } else {
  80. if(end.compare_exchange_strong(ed, node)) {
  81. start.store(node);
  82. node->release();
  83. return true;
  84. } else {
  85. return false;
  86. }
  87. }
  88. }
  89. };
  90. }