A C++ library for logging very fast and without allocating.
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

166 рядки
4.2 KiB

  1. #include "registry.h"
  2. #include "disruptor.h"
  3. #include "sl/register.h"
  4. #include <concepts>
  5. #include <atomic>
  6. #include <unordered_map>
  7. #include <functional>
  8. #include <any>
  9. /**
  10. * @brief A fast semaphore exclusion handler WITHOUT deadlock detection or yielding
  11. */
  12. template<std::integral T, T default_increment, T maximum_increment>
  13. class fast_semaphore {
  14. std::atomic<T> flag; //< This is our counter
  15. public:
  16. fast_semaphore() = default;
  17. fast_semaphore(fast_semaphore&) = delete;
  18. fast_semaphore(fast_semaphore&&) = delete;
  19. /// 3 things may happen when trying to unlock
  20. enum class tristate {
  21. success = 1, //< The unlocking was successful
  22. timing = 0, //< Someone interfered with the unlocking
  23. error = -1 //< The unlocking would over-unlock the semaphore
  24. };
  25. /// We try locking until we succeed
  26. template<T increment = default_increment>
  27. void lock() {
  28. while(not try_lock<increment>());
  29. }
  30. /// For locking, we try to atomically increment the counter while maintaining it below the set limit
  31. template<T increment = default_increment>
  32. [[nodiscard]] bool try_lock() {
  33. T expect = flag.load(std::memory_order::acquire);
  34. T target = expect + increment;
  35. if(target > maximum_increment) return false;
  36. return flag.compare_exchange_strong(expect,target,std::memory_order::release);
  37. }
  38. /// Similarly to locking, we try unlocking until we succeed (or reach an invalid state)
  39. template<T increment = default_increment>
  40. void unlock() {
  41. tristate v;
  42. do{ v = try_unlock<increment>(); }
  43. while(v == tristate::timing);
  44. if(v != tristate::success) {
  45. throw std::runtime_error("Over unlocking may have happened: potential double unlocking issue");
  46. }
  47. }
  48. /// Unlocking is the reverse of locking, we have to ensure to return an error if we try to go below zero
  49. template<T increment = default_increment>
  50. [[nodiscard]] tristate try_unlock() {
  51. T expect = flag.load(std::memory_order::relaxed);
  52. T target = expect - increment;
  53. if(target < 0) return tristate::error;
  54. return flag.compare_exchange_strong(expect,target,std::memory_order::release) ? tristate::success : tristate::timing;
  55. }
  56. };
  57. using rw_lock_type = fast_semaphore<int32_t, 256, 256>;
  58. class lock_handler_read {
  59. rw_lock_type& ref;
  60. explicit lock_handler_read(rw_lock_type& _ref) : ref(_ref) {
  61. while(ref.try_lock<1>());
  62. }
  63. ~lock_handler_read() {
  64. while(ref.try_unlock<1>() != rw_lock_type::tristate::success);
  65. }
  66. };
  67. class lock_handler_write {
  68. rw_lock_type& ref;
  69. explicit lock_handler_write(rw_lock_type& _ref) : ref(_ref) {
  70. while(ref.try_lock());
  71. }
  72. ~lock_handler_write() {
  73. while(ref.try_unlock() != rw_lock_type::tristate::success);
  74. }
  75. };
  76. static fast_semaphore<int32_t, 256, 256> registry_rw_lock;
  77. struct registry_slab {
  78. int id;
  79. std::string name;
  80. std::function<token_t(size_t)> reserve_write;
  81. std::function<token_t(size_t)> reserve_write_c_align;
  82. std::function<void(token_t)> conclude_write;
  83. std::any disruptor;
  84. };
  85. /**
  86. * @internal used because we need the pointer stability
  87. * @see sl_transaction
  88. */
  89. static std::unordered_map<int, registry_slab> registry_map;
  90. BufferStrategyInternal::buffer_type BufferStrategyInternal::build_buffer(size_t) {
  91. return {};
  92. }
  93. BufferStrategyShared::buffer_type BufferStrategyShared::build_buffer(size_t) {
  94. return {};
  95. }
  96. BufferStrategyExternal::buffer_type BufferStrategyExternal::build_buffer(size_t) {
  97. return {};
  98. }
  99. void SinkStrategyDirect::write(int fd, std::string_view data) {
  100. }
  101. void SinkStrategyFastest::write(int fd, std::string_view data) {
  102. }
  103. void SinkStrategyMmaped::write(int fd, std::string_view data) {
  104. }
  105. void SinkStrategyExternal::write(int fd, std::string_view data) {
  106. }
  107. void OverflowStrategyWait::wait() {
  108. }
  109. void OverflowStrategyContinue::wait() {
  110. }
  111. std::pair<std::string_view, std::string_view> OutputStrategyTimed::chunk(std::string_view) {
  112. return {};
  113. }
  114. int OutputStrategyTimed::on_write_completed_event(std::string_view, int) {
  115. return 0;
  116. }
  117. std::pair<std::string_view, std::string_view> OutputStrategySized::chunk(std::string_view) {
  118. return {};
  119. }
  120. int OutputStrategySized::on_write_completed_event(std::string_view, int) {
  121. return 0;
  122. }
  123. std::pair<std::string_view, std::string_view> OutputStrategySimple::chunk(std::string_view) {
  124. return {};
  125. }
  126. int OutputStrategySimple::on_write_completed_event(std::string_view, int) {
  127. return 0;
  128. }