A C++ library for logging very fast and without allocating.
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.
 
 
 

166 lines
4.2 KiB

#include "registry.h"
#include "disruptor.h"
#include "sl/register.h"
#include <concepts>
#include <atomic>
#include <unordered_map>
#include <functional>
#include <any>
/**
* @brief A fast semaphore exclusion handler WITHOUT deadlock detection or yielding
*/
template<std::integral T, T default_increment, T maximum_increment>
class fast_semaphore {
std::atomic<T> 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<T increment = default_increment>
void lock() {
while(not try_lock<increment>());
}
/// For locking, we try to atomically increment the counter while maintaining it below the set limit
template<T increment = default_increment>
[[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<T increment = default_increment>
void unlock() {
tristate v;
do{ v = try_unlock<increment>(); }
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<T increment = default_increment>
[[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<int32_t, 256, 256>;
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<int32_t, 256, 256> registry_rw_lock;
struct registry_slab {
int id;
std::string name;
std::function<token_t(size_t)> reserve_write;
std::function<token_t(size_t)> reserve_write_c_align;
std::function<void(token_t)> conclude_write;
std::any disruptor;
};
/**
* @internal used because we need the pointer stability
* @see sl_transaction
*/
static std::unordered_map<int, registry_slab> 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<std::string_view, std::string_view> OutputStrategyTimed::chunk(std::string_view) {
return {};
}
int OutputStrategyTimed::on_write_completed_event(std::string_view, int) {
return 0;
}
std::pair<std::string_view, std::string_view> OutputStrategySized::chunk(std::string_view) {
return {};
}
int OutputStrategySized::on_write_completed_event(std::string_view, int) {
return 0;
}
std::pair<std::string_view, std::string_view> OutputStrategySimple::chunk(std::string_view) {
return {};
}
int OutputStrategySimple::on_write_completed_event(std::string_view, int) {
return 0;
}