#include "registry.h" #include "disruptor.h" #include "sl/register.h" #include #include #include #include #include /** * @brief A fast semaphore exclusion handler WITHOUT deadlock detection or yielding */ template class fast_semaphore { std::atomic flag; //< This is our counter public: fast_semaphore() = default; fast_semaphore(fast_semaphore&) = delete; fast_semaphore(fast_semaphore&&) = delete; /// 3 things may happen when trying to unlock enum class tristate { success = 1, //< The unlocking was successful timing = 0, //< Someone interfered with the unlocking error = -1 //< The unlocking would over-unlock the semaphore }; /// We try locking until we succeed template void lock() { while(not try_lock()); } /// For locking, we try to atomically increment the counter while maintaining it below the set limit template [[nodiscard]] bool try_lock() { T expect = flag.load(std::memory_order::acquire); T target = expect + increment; if(target > maximum_increment) return false; return flag.compare_exchange_strong(expect,target,std::memory_order::release); } /// Similarly to locking, we try unlocking until we succeed (or reach an invalid state) template void unlock() { tristate v; do{ v = try_unlock(); } while(v == tristate::timing); if(v != tristate::success) { throw std::runtime_error("Over unlocking may have happened: potential double unlocking issue"); } } /// Unlocking is the reverse of locking, we have to ensure to return an error if we try to go below zero template [[nodiscard]] tristate try_unlock() { T expect = flag.load(std::memory_order::relaxed); T target = expect - increment; if(target < 0) return tristate::error; return flag.compare_exchange_strong(expect,target,std::memory_order::release) ? tristate::success : tristate::timing; } }; using rw_lock_type = fast_semaphore; class lock_handler_read { rw_lock_type& ref; explicit lock_handler_read(rw_lock_type& _ref) : ref(_ref) { while(ref.try_lock<1>()); } ~lock_handler_read() { while(ref.try_unlock<1>() != rw_lock_type::tristate::success); } }; class lock_handler_write { rw_lock_type& ref; explicit lock_handler_write(rw_lock_type& _ref) : ref(_ref) { while(ref.try_lock()); } ~lock_handler_write() { while(ref.try_unlock() != rw_lock_type::tristate::success); } }; static fast_semaphore registry_rw_lock; struct registry_slab { int id; std::string name; std::function reserve_write; std::function reserve_write_c_align; std::function conclude_write; std::any disruptor; }; /** * @internal used because we need the pointer stability * @see sl_transaction */ static std::unordered_map registry_map; BufferStrategyInternal::buffer_type BufferStrategyInternal::build_buffer(size_t) { return {}; } BufferStrategyShared::buffer_type BufferStrategyShared::build_buffer(size_t) { return {}; } BufferStrategyExternal::buffer_type BufferStrategyExternal::build_buffer(size_t) { return {}; } void SinkStrategyDirect::write(int fd, std::string_view data) { } void SinkStrategyFastest::write(int fd, std::string_view data) { } void SinkStrategyMmaped::write(int fd, std::string_view data) { } void SinkStrategyExternal::write(int fd, std::string_view data) { } void OverflowStrategyWait::wait() { } void OverflowStrategyContinue::wait() { } std::pair OutputStrategyTimed::chunk(std::string_view) { return {}; } int OutputStrategyTimed::on_write_completed_event(std::string_view, int) { return 0; } std::pair OutputStrategySized::chunk(std::string_view) { return {}; } int OutputStrategySized::on_write_completed_event(std::string_view, int) { return 0; } std::pair OutputStrategySimple::chunk(std::string_view) { return {}; } int OutputStrategySimple::on_write_completed_event(std::string_view, int) { return 0; }