concurrentqueue
concurrentqueue copied to clipboard
loop panic
code:
struct LogEvent {
std::string fmt;
void *udata;
std::string file_path;
int line;
SlogLevel level;
std::string tag;
int syslog_triger;
explicit LogEvent(std::string fmt, void *udata, std::string file_path, int line, SlogLevel level, std::string tag,
int syslog_triger = 0)
: fmt(std::move(fmt)),
udata(udata),
file_path(std::move(file_path)),
line(line),
level(level),
tag(std::move(tag)),
syslog_triger(syslog_triger) {}
};
moodycamel::ConcurrentQueue<LogEvent> log_buffer_;
static void LogToSyslog(const LogEvent &lev) {
auto log_t = fmt::format("{}: {}", lev.tag, lev.fmt);
syslog(LoggerTools::LevelSyslog(lev.level), "%s", log_t.c_str());
}
int main() {
const LogEvent lev{
formatted, nullptr, file, line, level, tag,
};
log_buffer_.enqueue(lev);
while (log_buffer_.size_approx() > 0) {
LogEvent lev{"", nullptr, "", 0, SlogLevel::DEBUG, ""};
auto ret = log_buffer_.try_dequeue(lev);
if (!ret) {
continue;
}
if (lev.level >= default_level_) {
LogToSyslog(lev);
}
}
}
panic info:
#0 std::__atomic_base<unsigned long>::load (__m=std::memory_order_relaxed, this=0x8c618a53ab61cf75) at /home/sinsegye/.conan/data/gcc/8.4.0/_/_/package/c36389a16c86a80fda9a30c45330b881d7951813/include/c++/8.4.0/bits/atomic_base.h:396
#1 moodycamel::ConcurrentQueue<slog::LogEvent, moodycamel::ConcurrentQueueDefaultTraits>::ProducerBase::size_approx (this=0x8c618a53ab61cf55) at /home/sinsegye/.conan/data/concurrentqueue/1.0.4/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/moodycamel/concurrentqueue.h:1739
#2 0x000000000041721a in moodycamel::ConcurrentQueue<slog::LogEvent, moodycamel::ConcurrentQueueDefaultTraits>::size_approx (this=0x4a3860 <slog::Logger::instance()::inst>)
at /home/sinsegye/.conan/data/concurrentqueue/1.0.4/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/moodycamel/concurrentqueue.h:1329
#3 0x0000000000406b36 in slog::Logger::Worker (this=0x4a3860 <slog::Logger::instance()::inst>) at /home/sinsegye/workspace/apps/src/logger/logger.cc:75
#4 0x000000000041b54f in std::__invoke_impl<void, void (slog::Logger::*)(), slog::Logger*> (__f=@0x1397bd0: (void (slog::Logger::*)(slog::Logger * const)) 0x406acc <slog::Logger::Worker()>, __t=@0x1397bc8: 0x4a3860 <slog::Logger::instance()::inst>)
at /home/sinsegye/.conan/data/gcc/8.4.0/_/_/package/c36389a16c86a80fda9a30c45330b881d7951813/include/c++/8.4.0/bits/invoke.h:73
#5 0x0000000000417a95 in std::__invoke<void (slog::Logger::*)(), slog::Logger*> (__fn=@0x1397bd0: (void (slog::Logger::*)(slog::Logger * const)) 0x406acc <slog::Logger::Worker()>)
at /home/sinsegye/.conan/data/gcc/8.4.0/_/_/package/c36389a16c86a80fda9a30c45330b881d7951813/include/c++/8.4.0/bits/invoke.h:95
#6 0x000000000045ddae in std::thread::_Invoker<std::tuple<void (slog::Logger::*)(), slog::Logger*> >::_M_invoke<0ul, 1ul> (this=0x1397bc8) at /home/sinsegye/.conan/data/gcc/8.4.0/_/_/package/c36389a16c86a80fda9a30c45330b881d7951813/include/c++/8.4.0/thread:244
#7 0x000000000045d92e in std::thread::_Invoker<std::tuple<void (slog::Logger::*)(), slog::Logger*> >::operator() (this=0x1397bc8) at /home/sinsegye/.conan/data/gcc/8.4.0/_/_/package/c36389a16c86a80fda9a30c45330b881d7951813/include/c++/8.4.0/thread:253
#8 0x000000000045c50e in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (slog::Logger::*)(), slog::Logger*> > >::_M_run (this=0x1397bc0) at /home/sinsegye/.conan/data/gcc/8.4.0/_/_/package/c36389a16c86a80fda9a30c45330b881d7951813/include/c++/8.4.0/thread:196
#9 0x00007ac349537253 in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6
#10 0x00007ac3491bfac3 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#11 0x00007ac349250a04 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:100
The code you've shared seems fine at first glance. Callstack suggests something else is happening in code not shown here.
enum SYSLOGTRG : int {
DEFAULT,
ENABLE,
DISABLE,
};
auto Logger::IsLogBufferEmpty() -> bool { return log_buffer_.size_approx() == 0; }
auto Logger::SysLogEnable(SyslogType type) -> bool {
#ifdef _WIN32
init_syslog();
#endif
closelog();
switch (type) {
case APPLICATION:
openlog(nullptr, LOG_PID, LOG_LOCAL4);
break;
case SERVICE:
openlog(nullptr, LOG_PID, LOG_LOCAL3);
break;
case IO_DEVICES:
openlog(nullptr, LOG_PID, LOG_LOCAL0);
break;
case COMMUNICATION_BUS:
openlog(nullptr, LOG_PID, LOG_LOCAL1);
break;
case SAFETY_SYSTEMS:
openlog(nullptr, LOG_PID, LOG_LOCAL2);
break;
case RUNTIME:
openlog(nullptr, LOG_PID, LOG_LOCAL5);
break;
case SYSTEM_MAINTENANCE:
openlog(nullptr, LOG_PID, LOG_LOCAL6);
break;
case TEMPORARY_DEBUGGING:
openlog(nullptr, LOG_PID, LOG_LOCAL7);
break;
}
const LogEvent lev{"", nullptr, "", 0, SlogLevel::DEBUG, "", ENABLE};
log_buffer_.enqueue(lev);
return true;
}
void Logger::SysLogDisable() {
const LogEvent lev{"", nullptr, "", 0, SlogLevel::DEBUG, "", DISABLE};
log_buffer_.enqueue(lev);
closelog();
}
void Logger::Log(SlogLevel level, const std::string &tag, const std::string &file, int line,
const std::string &formatted) {
const LogEvent lev{
formatted, nullptr, file, line, level, tag,
};
log_buffer_.enqueue(lev);
}
void Logger::Worker() {
while (!stop_worker_) {
while (log_buffer_.size_approx() > 0) {
if (stop_worker_) {
break;
}
static std::atomic<bool> syslog{false};
LogEvent lev{"", nullptr, "", 0, SlogLevel::DEBUG, ""};
auto ret = log_buffer_.try_dequeue(lev);
if (!ret) {
continue;
}
switch (lev.syslog_triger) {
case ENABLE:
syslog.store(true);
continue;
case DISABLE:
syslog.store(false);
continue;
}
if (!quiet_ && lev.level >= default_level_) {
LogToStdout(lev);
}
if (syslog && lev.level >= default_level_) {
LogToSyslog(lev);
}
}
}
}
Logger::Logger() {
SysLogEnable(TEMPORARY_DEBUGGING);
std::thread worker_thread(&Logger::Worker, this);
worker_thread.detach();
}
void Logger::ResetLogBuffer() {
while (!IsLogBufferEmpty()) {
LogEvent lev{"", nullptr, "", 0, SlogLevel::DEBUG, ""};
auto ret = log_buffer_.try_dequeue(lev);
if (!ret) {
continue;
}
if (lev.level >= default_level_) {
LogToSyslog(lev);
}
}
}
Logger::~Logger() { // NOLINT(bugprone-exception-escape)
stop_worker_ = true;
ResetLogBuffer();
}
If log_buffer_ is a member of Logger, then Logger::~Logger is not safe, as log_buffer_ can be destroyed while it is still being used by the thread running Logger::Worker.