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.

109 lines
2.2 KiB

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