Make logger stop flag atomic

This commit is contained in:
Julien Letessier 2026-01-15 16:29:08 +01:00
parent 65c55be6cd
commit abe75e40a2
5 changed files with 67 additions and 5 deletions

View File

@ -122,7 +122,7 @@ void Logger::start()
void Logger::stop() void Logger::stop()
{ {
mStop = true; mStop.store(true);
std::unique_lock<std::mutex> lck(mMtx); std::unique_lock<std::mutex> lck(mMtx);
mCond.notify_one(); mCond.notify_one();
} }
@ -131,11 +131,11 @@ void Logger::run()
{ {
std::vector<LogUnit*> logs(mFree.capacity()); std::vector<LogUnit*> logs(mFree.capacity());
logs.resize(0); logs.resize(0);
while (!mStop) { while (!mStop.load()) {
long missLogs = 0; long missLogs = 0;
do { do {
std::unique_lock<std::mutex> lck(mMtx); std::unique_lock<std::mutex> lck(mMtx);
while (mLogs.empty() && !mStop) { while (mLogs.empty() && !mStop.load()) {
mCond.wait(lck); mCond.wait(lck);
} }
logs.swap(mLogs); logs.swap(mLogs);
@ -211,7 +211,7 @@ LogUnit* Logger::getLogUnit()
++mLogUnitCnt; ++mLogUnitCnt;
log = new LogUnit(); log = new LogUnit();
} else { } else {
while (mFree.empty() && !mStop) { while (mFree.empty() && !mStop.load()) {
mCond.wait(lck); mCond.wait(lck);
} }
if (!mFree.empty()) { if (!mFree.empty()) {

View File

@ -101,7 +101,7 @@ private:
LogUnit* getLogUnit(); LogUnit* getLogUnit();
void run(); void run();
private: private:
bool mStop; Atomic<bool> mStop;
bool mAllowMissLog; bool mAllowMissLog;
AtomicLong mMissLogs; AtomicLong mMissLogs;
int mLogSample[LogLevel::Sentinel]; int mLogSample[LogLevel::Sentinel];

View File

@ -0,0 +1,17 @@
/*
* Compile-only test to ensure Logger::mStop is atomic.
*/
#define private public
#include "../src/Logger.h"
#undef private
#include <type_traits>
#include <utility>
int main() {
using StopType = decltype(std::declval<Logger>().mStop);
static_assert(std::is_same<StopType, Atomic<bool>>::value,
"Logger::mStop should be atomic");
return 0;
}

View File

@ -0,0 +1,44 @@
#!/usr/bin/env python3
#
# Build and run the Logger::mStop atomic type check.
#
import os
import subprocess
import tempfile
from test_util import parse_args, exit_with_result
def run_test(project_root):
src = os.path.join(project_root, "test", "logger_stop_atomic.cpp")
if not os.path.exists(src):
print("FAIL: logger_stop_atomic.cpp not found")
return False
with tempfile.TemporaryDirectory() as tmp:
exe = os.path.join(tmp, "logger_stop_atomic")
cmd = [
"g++",
"-std=c++11",
src,
"-o",
exe,
]
try:
subprocess.check_call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
except Exception as exc:
print("FAIL: compile logger_stop_atomic:", exc)
return False
try:
subprocess.check_call([exe], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
except subprocess.CalledProcessError as exc:
print("FAIL: logger_stop_atomic returned", exc.returncode)
return False
return True
if __name__ == "__main__":
_ = parse_args("Logger stop atomic test")
root = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
success = run_test(root)
exit_with_result(success, "logger stop atomic", "logger stop atomic")

View File

@ -151,6 +151,7 @@ TESTS=(
"test/logger_unbounded_logunit.py" "test/logger_unbounded_logunit.py"
"test/string_to_int.py" "test/string_to_int.py"
"test/handler_stop_atomic.py" "test/handler_stop_atomic.py"
"test/logger_stop_atomic.py"
"test/pubsub_long_name.py" "test/pubsub_long_name.py"
"test/pubsub_large_message.py" "test/pubsub_large_message.py"
"test/transaction_forbid.py" "test/transaction_forbid.py"