A C++ library for logging very fast and without allocating.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

166 lignes
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. }