#include "RTLogger.hpp" #include #include "printf.h" RTLogger& RTLogger::get() { if(instance) { return *instance; } RTLogger * maybeInstance = new RTLogger(); RTLogger * expected = nullptr; if(!instance.compare_exchange_strong(expected, maybeInstance)) { // wasn't us delete maybeInstance; return *instance; } // was us, start thread maybeInstance->start(); return *instance; } void RTLogger::log(const char* format, ...) { #ifdef DEBUG constexpr const size_t bufsz = 512; char buf[bufsz]; va_list va; va_start(va, format); const int numbytes = vsnprintf_(buf, bufsz, format, va); va_end(va); RTLogger& inst = RTLogger::get(); if(numbytes < 0) { inst.q.try_emplace(message("(formatting failed)")); } else { inst.q.try_emplace(std::string(buf, std::min(bufsz, (size_t) numbytes))); } try { inst.sema.release(); } catch(std::system_error&) { } #endif } RTLogger::RTLogger() : q(1024), sema(0) { } RTLogger::~RTLogger() { } void RTLogger::start() { #ifdef DEBUG thread = std::make_unique([this]{ message msg; for(;;) { try { (void)sema.try_acquire_for(std::chrono::milliseconds(100)); } catch (std::system_error&) { } auto gotMsg = q.try_pop(msg); if(!gotMsg) { continue; } if(msg.shouldExit) { break; } std::cerr << msg.val << "\n"; } }); atexit([]{ RTLogger::get().stop(); }); #endif } void RTLogger::stop() { #ifdef DEBUG if(!thread || !thread->joinable()) { return; } q.emplace(message()); thread->join(); thread.reset(); #endif } std::atomic RTLogger::instance{nullptr};