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.

111 lines
3.1 KiB

3 years ago
  1. #pragma once
  2. #include <atomic>
  3. #include <concepts>
  4. #include "gp_config.hpp"
  5. namespace gp {
  6. /**
  7. * @brief CADR lock_guard for generic locking mechanisms
  8. *
  9. * @tparam T
  10. */
  11. template<typename T>
  12. class lock_guard {
  13. T& ref;
  14. public:
  15. lock_guard(T& _ref)
  16. : ref(_ref)
  17. {
  18. ref.lock();
  19. }
  20. ~lock_guard() {
  21. ref.unlock();
  22. }
  23. };
  24. /**
  25. * @brief A fast mutual exclusion handler WITHOUT deadlock detection
  26. */
  27. class fast_bottleneck {
  28. std::atomic_bool flag;
  29. public:
  30. fast_bottleneck() = default;
  31. fast_bottleneck(fast_bottleneck&) = delete;
  32. fast_bottleneck(fast_bottleneck&&) = delete;
  33. void lock() {
  34. while(not try_lock());
  35. }
  36. [[nodiscard]] bool try_lock() {
  37. bool f = false;
  38. bool t = true;
  39. return flag.compare_exchange_strong(f,t,std::memory_order::acquire);
  40. }
  41. void unlock() {
  42. gp_config::assertion(try_unlock(), "Unlocking failed in fast_bottleneck: potential double unlocking issue");
  43. }
  44. [[nodiscard]] bool try_unlock() {
  45. bool f = false;
  46. bool t = true;
  47. return flag.compare_exchange_strong(t,f,std::memory_order::release);
  48. }
  49. };
  50. /**
  51. * @brief A fast semaphore exclusion handler WITHOUT deadlock detection
  52. */
  53. template<std::integral T, T default_increment, T maximum_increment>
  54. class fast_semaphore {
  55. std::atomic<T> flag;
  56. public:
  57. fast_semaphore() = default;
  58. fast_semaphore(fast_semaphore&) = delete;
  59. fast_semaphore(fast_semaphore&&) = delete;
  60. enum class tristate {
  61. success,
  62. timing,
  63. error
  64. };
  65. void lock_super() {
  66. auto value = flag.fetch_add(maximum_increment, std::memory_order::relaxed);
  67. while(value > maximum_increment) { value = flag.load(std::memory_order::release); }
  68. }
  69. template<T increment = default_increment>
  70. void lock() {
  71. while(not try_lock<increment>());
  72. }
  73. template<T increment = default_increment>
  74. [[nodiscard]] bool try_lock() {
  75. T expect = flag.load(std::memory_order::relaxed);
  76. T target = expect + increment;
  77. if(target > maximum_increment) return false;
  78. return flag.compare_exchange_strong(expect,target,std::memory_order::acquire);
  79. }
  80. template<T increment = default_increment>
  81. void unlock() {
  82. tristate v;
  83. do{ v = try_unlock<increment>(); }
  84. while(v == tristate::timing);
  85. gp_config::assertion(v == tristate::success, "Over unlocking may have happened");
  86. }
  87. template<T increment = default_increment>
  88. [[nodiscard]] tristate try_unlock() {
  89. T expect = flag.load(std::memory_order::relaxed);
  90. T target = expect - increment;
  91. if(target < 0) return tristate::error;
  92. return flag.compare_exchange_strong(expect,target,std::memory_order::release) ? tristate::success : tristate::timing;
  93. }
  94. };
  95. }