General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

107 lines
2.2 KiB

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