diff --git a/common/log.h b/common/log.h index f48a2956e..412824024 100644 --- a/common/log.h +++ b/common/log.h @@ -50,7 +50,9 @@ // // -------------------------------- +#ifdef LOG_WITH_TEST inline void log_test(); +#endif class LogTargetWrapper { @@ -68,6 +70,7 @@ class LogTargetWrapper LogTargetWrapper( const std::string && filename ) : LogTargetWrapper(filename) {} + LogTargetWrapper( const std::string & filename ) : _filename(filename) { @@ -88,7 +91,7 @@ class LogTargetWrapper if(_type == Type::File && _handle != nullptr) {std::fclose(_handle);} } - enum Type{ + enum class Type{ Invalid, File, Stream @@ -97,20 +100,10 @@ class LogTargetWrapper public: operator FILE*() { - // Assigning lambda result to a static variable guarantees one time thread-safe execution - // 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 lock(_mutex); + if(!_opened) + { 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"); if( result ) @@ -126,14 +119,12 @@ class LogTargetWrapper _opened = true; } _lock.clear(std::memory_order_release); - return _opened.load(); - }(); + } return _handle; } void flush() { - //std::lock_guard lock(_mutex); while( _lock.test_and_set(std::memory_order_acquire) ){ std::this_thread::yield(); } if(_opened && _type != Type::Invalid && _handle) { @@ -143,7 +134,6 @@ class LogTargetWrapper } private: - //std::mutex _mutex; std::atomic_flag _lock = ATOMIC_FLAG_INIT; Type _type {Type::Invalid}; std::string _filename; @@ -153,11 +143,17 @@ class LogTargetWrapper // Utility for synchronizing log configuration state // since std::optional was introduced only in c++17 -enum LogTriState +enum class LogTriState { - LogTriStateSame, - LogTriStateFalse, - LogTriStateTrue + Same, + False, + True +}; + +enum class LogTargetChannel +{ + Logfile, + Screen }; class LogStateWrapper @@ -184,16 +180,15 @@ class LogStateWrapper private: std::mutex _mutex; + std::atomic_flag _lock = ATOMIC_FLAG_INIT; std::atomic _enabled {true}; - std::atomic _global_override_enabled {LogTriState::LogTriStateSame}; + std::atomic _global_override_enabled {LogTriState::Same}; std::set _targets; LogTargetWrapper _null_target {nullptr}; LogTargetWrapper _stderr_target {stderr}; - std::atomic _global_override_target {LogTriState::LogTriStateSame}; + std::atomic _global_override_target {LogTriState::Same}; std::atomic _current_target {&_null_target}; - std::atomic _current_tee_target {&_stderr_target}; std::atomic _stored_target {&_null_target}; - std::atomic _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_add_select_target(new LogTargetWrapper(filename));} @@ -203,14 +198,14 @@ class LogStateWrapper log_flush_all_targets(); std::lock_guard 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 _stored_target; } - if(_enabled || _global_override_enabled == LogTriState::LogTriStateTrue) + if(_enabled || _global_override_enabled == LogTriState::True) { _current_target.store(target); } @@ -222,39 +217,19 @@ class LogStateWrapper 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 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) { log_flush_all_targets(); std::lock_guard 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 _stored_target; } - if(_enabled || _global_override_enabled == LogTriState::LogTriStateTrue) + if(_enabled || _global_override_enabled == LogTriState::True) { _current_target.store(t); } @@ -267,24 +242,6 @@ class LogStateWrapper return t; } - LogTargetWrapper* log_add_select_tee_target(LogTargetWrapper* t) - { - log_flush_all_targets(); - std::lock_guard 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() { std::lock_guard lock(_mutex); @@ -298,7 +255,7 @@ class LogStateWrapper FILE* log_tee_handler_impl() { - return *_current_tee_target; + return _stderr_target; } void log_disable_impl( bool threadsafe = true ) @@ -316,12 +273,10 @@ class LogStateWrapper 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_tee_target.store (_current_tee_target); _current_target.store (&_null_target); - _current_tee_target.store (&_stderr_target); _enabled = false; } } @@ -341,10 +296,9 @@ class LogStateWrapper 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_tee_target.store (_stored_tee_target); _enabled = true; } } @@ -363,7 +317,7 @@ class LogStateWrapper { std::lock_guard lock(_mutex); log_disable_impl_unsafe(); - _global_override_enabled = LogTriState::LogTriStateFalse; + _global_override_enabled = LogTriState::False; } return true; } @@ -373,7 +327,7 @@ class LogStateWrapper { std::lock_guard lock(_mutex); log_enable_impl_unsafe(); - _global_override_enabled = LogTriState::LogTriStateTrue; + _global_override_enabled = LogTriState::True; } return true; } @@ -399,7 +353,7 @@ class LogStateWrapper _stored_target.store(t); } _targets.insert(t); - _global_override_target = LogTriState::LogTriStateTrue; + _global_override_target = LogTriState::True; 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( 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_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_tee_handler() {return instance().log_tee_handler_impl();} static void log_disable() {instance().log_disable_impl();}