simplify tee funcs, LogTargetWrapper yield lock

This commit is contained in:
staviq 2023-09-16 18:17:53 +02:00
parent 65116c6015
commit 71c49a692a

View file

@ -50,7 +50,9 @@
// //
// -------------------------------- // --------------------------------
#ifdef LOG_WITH_TEST
inline void log_test(); inline void log_test();
#endif
class LogTargetWrapper class LogTargetWrapper
{ {
@ -68,6 +70,7 @@ class LogTargetWrapper
LogTargetWrapper( const std::string && filename ) LogTargetWrapper( const std::string && filename )
: LogTargetWrapper(filename) : LogTargetWrapper(filename)
{} {}
LogTargetWrapper( const std::string & filename ) LogTargetWrapper( const std::string & filename )
: _filename(filename) : _filename(filename)
{ {
@ -88,7 +91,7 @@ class LogTargetWrapper
if(_type == Type::File && _handle != nullptr) {std::fclose(_handle);} if(_type == Type::File && _handle != nullptr) {std::fclose(_handle);}
} }
enum Type{ enum class Type{
Invalid, Invalid,
File, File,
Stream Stream
@ -97,20 +100,10 @@ class LogTargetWrapper
public: public:
operator FILE*() operator FILE*()
{ {
// Assigning lambda result to a static variable guarantees one time thread-safe execution if(!_opened)
// while completly removing the need for conditional if(initialized). {
//
// This noticeably reduces performance overhead of LOG macro invocations.
//
// Initializing log file here, prevents creating a file before first LOG use,
// simplifying initial conditions and overrides from command line arguments.
//
// TODO: MSVC
//
static const auto dummy_init __attribute__((unused)) = [&](){
//std::lock_guard<std::mutex> lock(_mutex);
while( _lock.test_and_set(std::memory_order_acquire) ){ std::this_thread::yield(); } while( _lock.test_and_set(std::memory_order_acquire) ){ std::this_thread::yield(); }
if(!_opened && _type == Type::File) if(!_opened && _type == Type::File) // check for opened again after acquiring a lock
{ {
auto result = std::fopen(_filename.c_str(), "w"); auto result = std::fopen(_filename.c_str(), "w");
if( result ) if( result )
@ -126,14 +119,12 @@ class LogTargetWrapper
_opened = true; _opened = true;
} }
_lock.clear(std::memory_order_release); _lock.clear(std::memory_order_release);
return _opened.load(); }
}();
return _handle; return _handle;
} }
void flush() void flush()
{ {
//std::lock_guard<std::mutex> lock(_mutex);
while( _lock.test_and_set(std::memory_order_acquire) ){ std::this_thread::yield(); } while( _lock.test_and_set(std::memory_order_acquire) ){ std::this_thread::yield(); }
if(_opened && _type != Type::Invalid && _handle) if(_opened && _type != Type::Invalid && _handle)
{ {
@ -143,7 +134,6 @@ class LogTargetWrapper
} }
private: private:
//std::mutex _mutex;
std::atomic_flag _lock = ATOMIC_FLAG_INIT; std::atomic_flag _lock = ATOMIC_FLAG_INIT;
Type _type {Type::Invalid}; Type _type {Type::Invalid};
std::string _filename; std::string _filename;
@ -153,11 +143,17 @@ class LogTargetWrapper
// Utility for synchronizing log configuration state // Utility for synchronizing log configuration state
// since std::optional was introduced only in c++17 // since std::optional was introduced only in c++17
enum LogTriState enum class LogTriState
{ {
LogTriStateSame, Same,
LogTriStateFalse, False,
LogTriStateTrue True
};
enum class LogTargetChannel
{
Logfile,
Screen
}; };
class LogStateWrapper class LogStateWrapper
@ -184,16 +180,15 @@ class LogStateWrapper
private: private:
std::mutex _mutex; std::mutex _mutex;
std::atomic_flag _lock = ATOMIC_FLAG_INIT;
std::atomic<bool> _enabled {true}; std::atomic<bool> _enabled {true};
std::atomic<LogTriState> _global_override_enabled {LogTriState::LogTriStateSame}; std::atomic<LogTriState> _global_override_enabled {LogTriState::Same};
std::set<LogTargetWrapper*> _targets; std::set<LogTargetWrapper*> _targets;
LogTargetWrapper _null_target {nullptr}; LogTargetWrapper _null_target {nullptr};
LogTargetWrapper _stderr_target {stderr}; LogTargetWrapper _stderr_target {stderr};
std::atomic<LogTriState> _global_override_target {LogTriState::LogTriStateSame}; std::atomic<LogTriState> _global_override_target {LogTriState::Same};
std::atomic<LogTargetWrapper*> _current_target {&_null_target}; std::atomic<LogTargetWrapper*> _current_target {&_null_target};
std::atomic<LogTargetWrapper*> _current_tee_target {&_stderr_target};
std::atomic<LogTargetWrapper*> _stored_target {&_null_target}; std::atomic<LogTargetWrapper*> _stored_target {&_null_target};
std::atomic<LogTargetWrapper*> _stored_tee_target {&_null_target};
LogTargetWrapper* log_set_target_impl( const std::string && filename ) {return log_set_target_impl(filename);} LogTargetWrapper* log_set_target_impl( const std::string && filename ) {return log_set_target_impl(filename);}
LogTargetWrapper* log_set_target_impl( const std::string & filename ) {return log_add_select_target(new LogTargetWrapper(filename));} LogTargetWrapper* log_set_target_impl( const std::string & filename ) {return log_add_select_target(new LogTargetWrapper(filename));}
@ -203,14 +198,14 @@ class LogStateWrapper
log_flush_all_targets(); log_flush_all_targets();
std::lock_guard<std::mutex> lock(_mutex); std::lock_guard<std::mutex> lock(_mutex);
if( _global_override_target == LogTriState::LogTriStateTrue ) if( _global_override_target == LogTriState::True )
{ {
if(_enabled || _global_override_enabled == LogTriState::LogTriStateTrue) if(_enabled || _global_override_enabled == LogTriState::True)
return _current_target; return _current_target;
return _stored_target; return _stored_target;
} }
if(_enabled || _global_override_enabled == LogTriState::LogTriStateTrue) if(_enabled || _global_override_enabled == LogTriState::True)
{ {
_current_target.store(target); _current_target.store(target);
} }
@ -222,39 +217,19 @@ class LogStateWrapper
return target; return target;
} }
LogTargetWrapper* log_set_tee_target_impl( const std::string && filename ) {return log_set_tee_target_impl(filename);}
LogTargetWrapper* log_set_tee_target_impl( const std::string & filename ) {return log_add_select_tee_target(new LogTargetWrapper(filename));}
LogTargetWrapper* log_set_tee_target_impl( FILE* handle ) {return log_add_select_tee_target(new LogTargetWrapper(handle));}
LogTargetWrapper* log_set_tee_target_impl( LogTargetWrapper * target )
{
log_flush_all_targets();
std::lock_guard<std::mutex> lock(_mutex);
if(_enabled || _global_override_enabled == LogTriState::LogTriStateTrue)
{
_current_tee_target.store(target);
}
else
{
_stored_tee_target.store(target);
}
return target;
}
LogTargetWrapper* log_add_select_target(LogTargetWrapper* t) LogTargetWrapper* log_add_select_target(LogTargetWrapper* t)
{ {
log_flush_all_targets(); log_flush_all_targets();
std::lock_guard<std::mutex> lock(_mutex); std::lock_guard<std::mutex> lock(_mutex);
if( _global_override_target ) if( _global_override_target == LogTriState::True)
{ {
if(_enabled || _global_override_enabled == LogTriState::LogTriStateTrue) if(_enabled || _global_override_enabled == LogTriState::True)
return _current_target; return _current_target;
return _stored_target; return _stored_target;
} }
if(_enabled || _global_override_enabled == LogTriState::LogTriStateTrue) if(_enabled || _global_override_enabled == LogTriState::True)
{ {
_current_target.store(t); _current_target.store(t);
} }
@ -267,24 +242,6 @@ class LogStateWrapper
return t; return t;
} }
LogTargetWrapper* log_add_select_tee_target(LogTargetWrapper* t)
{
log_flush_all_targets();
std::lock_guard<std::mutex> lock(_mutex);
if(_enabled || _global_override_enabled == LogTriState::LogTriStateTrue)
{
_current_tee_target.store(t);
}
else
{
_stored_tee_target.store(t);
}
_targets.insert(t);
return t;
}
void log_flush_all_targets() void log_flush_all_targets()
{ {
std::lock_guard<std::mutex> lock(_mutex); std::lock_guard<std::mutex> lock(_mutex);
@ -298,7 +255,7 @@ class LogStateWrapper
FILE* log_tee_handler_impl() FILE* log_tee_handler_impl()
{ {
return *_current_tee_target; return _stderr_target;
} }
void log_disable_impl( bool threadsafe = true ) void log_disable_impl( bool threadsafe = true )
@ -316,12 +273,10 @@ class LogStateWrapper
void log_disable_impl_unsafe() void log_disable_impl_unsafe()
{ {
if(_enabled && _global_override_enabled != LogTriState::LogTriStateTrue) if(_enabled && _global_override_enabled != LogTriState::True)
{ {
_stored_target.store (_current_target); _stored_target.store (_current_target);
_stored_tee_target.store (_current_tee_target);
_current_target.store (&_null_target); _current_target.store (&_null_target);
_current_tee_target.store (&_stderr_target);
_enabled = false; _enabled = false;
} }
} }
@ -341,10 +296,9 @@ class LogStateWrapper
void log_enable_impl_unsafe() void log_enable_impl_unsafe()
{ {
if(!_enabled && _global_override_enabled != LogTriState::LogTriStateFalse) if(!_enabled && _global_override_enabled != LogTriState::False)
{ {
_current_target.store (_stored_target); _current_target.store (_stored_target);
_current_tee_target.store (_stored_tee_target);
_enabled = true; _enabled = true;
} }
} }
@ -363,7 +317,7 @@ class LogStateWrapper
{ {
std::lock_guard<std::mutex> lock(_mutex); std::lock_guard<std::mutex> lock(_mutex);
log_disable_impl_unsafe(); log_disable_impl_unsafe();
_global_override_enabled = LogTriState::LogTriStateFalse; _global_override_enabled = LogTriState::False;
} }
return true; return true;
} }
@ -373,7 +327,7 @@ class LogStateWrapper
{ {
std::lock_guard<std::mutex> lock(_mutex); std::lock_guard<std::mutex> lock(_mutex);
log_enable_impl_unsafe(); log_enable_impl_unsafe();
_global_override_enabled = LogTriState::LogTriStateTrue; _global_override_enabled = LogTriState::True;
} }
return true; return true;
} }
@ -399,7 +353,7 @@ class LogStateWrapper
_stored_target.store(t); _stored_target.store(t);
} }
_targets.insert(t); _targets.insert(t);
_global_override_target = LogTriState::LogTriStateTrue; _global_override_target = LogTriState::True;
return t; return t;
} }
@ -443,10 +397,6 @@ class LogStateWrapper
static LogTargetWrapper* log_set_target( const std::string & filename ) {return instance().log_set_target_impl(filename);} static LogTargetWrapper* log_set_target( const std::string & filename ) {return instance().log_set_target_impl(filename);}
static LogTargetWrapper* log_set_target( FILE* handle ) {return instance().log_set_target_impl(handle);} static LogTargetWrapper* log_set_target( FILE* handle ) {return instance().log_set_target_impl(handle);}
static LogTargetWrapper* log_set_target( LogTargetWrapper * target ) {return instance().log_set_target_impl(target);} static LogTargetWrapper* log_set_target( LogTargetWrapper * target ) {return instance().log_set_target_impl(target);}
static LogTargetWrapper* log_set_tee_target( const std::string && filename ) {return log_set_tee_target(filename);}
static LogTargetWrapper* log_set_tee_target( const std::string & filename ) {return instance().log_set_tee_target_impl(filename);}
static LogTargetWrapper* log_set_tee_target( FILE* handle ) {return instance().log_set_tee_target_impl(handle);}
static LogTargetWrapper* log_set_tee_target( LogTargetWrapper * target ) {return instance().log_set_tee_target_impl(target);}
static FILE* log_handler() {return instance().log_handler_impl();} static FILE* log_handler() {return instance().log_handler_impl();}
static FILE* log_tee_handler() {return instance().log_tee_handler_impl();} static FILE* log_tee_handler() {return instance().log_tee_handler_impl();}
static void log_disable() {instance().log_disable_impl();} static void log_disable() {instance().log_disable_impl();}