forked from lix-project/lix
fix the logger leaks
Passing around the loggers as raw pointers or references everywhere is really
error prone, so they were just leaked all over the place. Introduce unique
ownership instead so that they are properly freed when no longer needed (for
example, when a different logger is created or the program is terminated).
Of course, actually exercising the destructors uncovered a bug in ProgressBar,
where creating it in inactive state (on a non-TTY stderr) resulted in the
update thread starting anyway, violating the invariant required by the
destructor. This had to be fixed too.
Change-Id: I372cb710aaca492c2adcd8241f1a8e57221b5d16
This commit is contained in:
parent
49623818c7
commit
537319e3b3
|
@ -60,7 +60,7 @@ static bool allSupportedLocally(Store & store, const std::set<std::string>& requ
|
||||||
static int main_build_remote(int argc, char * * argv)
|
static int main_build_remote(int argc, char * * argv)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
logger = makeJSONLogger(*logger);
|
logger = makeJSONLogger(std::move(logger));
|
||||||
|
|
||||||
/* Ensure we don't get any SSH passphrase or host key popups. */
|
/* Ensure we don't get any SSH passphrase or host key popups. */
|
||||||
unsetenv("DISPLAY");
|
unsetenv("DISPLAY");
|
||||||
|
|
|
@ -24,14 +24,14 @@ LogFormat parseLogFormat(const std::string & logFormatStr) {
|
||||||
throw Error("option 'log-format' has an invalid value '%s'", logFormatStr);
|
throw Error("option 'log-format' has an invalid value '%s'", logFormatStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger * makeDefaultLogger() {
|
std::unique_ptr<Logger> makeDefaultLogger() {
|
||||||
switch (defaultLogFormat) {
|
switch (defaultLogFormat) {
|
||||||
case LogFormat::raw:
|
case LogFormat::raw:
|
||||||
return makeSimpleLogger(false);
|
return makeSimpleLogger(false);
|
||||||
case LogFormat::rawWithLogs:
|
case LogFormat::rawWithLogs:
|
||||||
return makeSimpleLogger(true);
|
return makeSimpleLogger(true);
|
||||||
case LogFormat::internalJSON:
|
case LogFormat::internalJSON:
|
||||||
return makeJSONLogger(*makeSimpleLogger(true));
|
return makeJSONLogger(makeSimpleLogger(true));
|
||||||
case LogFormat::bar:
|
case LogFormat::bar:
|
||||||
return makeProgressBar();
|
return makeProgressBar();
|
||||||
case LogFormat::barWithLogs: {
|
case LogFormat::barWithLogs: {
|
||||||
|
|
|
@ -44,17 +44,20 @@ static std::string_view storePathToName(std::string_view path)
|
||||||
ProgressBar::ProgressBar(bool isTTY)
|
ProgressBar::ProgressBar(bool isTTY)
|
||||||
: isTTY(isTTY)
|
: isTTY(isTTY)
|
||||||
{
|
{
|
||||||
state_.lock()->active = isTTY;
|
if ((state_.lock()->active = isTTY)) {
|
||||||
updateThread = std::thread([&]() {
|
// Only start the update thread when the logger is set to active.
|
||||||
auto state(state_.lock());
|
// Otherwise, the destructor will std::terminate trying to destroy a joinable thread.
|
||||||
auto nextWakeup = A_LONG_TIME;
|
updateThread = std::thread([&]() {
|
||||||
while (state->active) {
|
auto state(state_.lock());
|
||||||
if (!state->haveUpdate)
|
auto nextWakeup = A_LONG_TIME;
|
||||||
state.wait_for(updateCV, nextWakeup);
|
while (state->active) {
|
||||||
nextWakeup = draw(*state, {});
|
if (!state->haveUpdate)
|
||||||
state.wait_for(quitCV, std::chrono::milliseconds(50));
|
state.wait_for(updateCV, nextWakeup);
|
||||||
}
|
nextWakeup = draw(*state, {});
|
||||||
});
|
state.wait_for(quitCV, std::chrono::milliseconds(50));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgressBar::~ProgressBar()
|
ProgressBar::~ProgressBar()
|
||||||
|
@ -554,9 +557,9 @@ void ProgressBar::setPrintMultiline(bool printMultiline)
|
||||||
this->printMultiline = printMultiline;
|
this->printMultiline = printMultiline;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger * makeProgressBar()
|
std::unique_ptr<Logger> makeProgressBar()
|
||||||
{
|
{
|
||||||
return new ProgressBar(shouldANSI());
|
return std::make_unique<ProgressBar>(shouldANSI());
|
||||||
}
|
}
|
||||||
|
|
||||||
void startProgressBar()
|
void startProgressBar()
|
||||||
|
@ -566,7 +569,7 @@ void startProgressBar()
|
||||||
|
|
||||||
void stopProgressBar()
|
void stopProgressBar()
|
||||||
{
|
{
|
||||||
auto progressBar = dynamic_cast<ProgressBar *>(logger);
|
auto progressBar = dynamic_cast<ProgressBar *>(logger.get());
|
||||||
if (progressBar) progressBar->stop();
|
if (progressBar) progressBar->stop();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,7 +111,7 @@ struct ProgressBar : public Logger
|
||||||
void setPrintMultiline(bool printMultiline) override;
|
void setPrintMultiline(bool printMultiline) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
Logger * makeProgressBar();
|
std::unique_ptr<Logger> makeProgressBar();
|
||||||
|
|
||||||
void startProgressBar();
|
void startProgressBar();
|
||||||
|
|
||||||
|
|
|
@ -2636,7 +2636,7 @@ void LocalDerivationGoal::runChild()
|
||||||
/* Execute the program. This should not return. */
|
/* Execute the program. This should not return. */
|
||||||
if (drv->isBuiltin()) {
|
if (drv->isBuiltin()) {
|
||||||
try {
|
try {
|
||||||
logger = makeJSONLogger(*logger);
|
logger = makeJSONLogger(std::move(logger));
|
||||||
|
|
||||||
BasicDerivation & drv2(*drv);
|
BasicDerivation & drv2(*drv);
|
||||||
for (auto & e : drv2.env)
|
for (auto & e : drv2.env)
|
||||||
|
|
|
@ -991,11 +991,13 @@ void processConnection(
|
||||||
if (clientVersion < MIN_SUPPORTED_WORKER_PROTO_VERSION)
|
if (clientVersion < MIN_SUPPORTED_WORKER_PROTO_VERSION)
|
||||||
throw Error("the Nix client version is too old");
|
throw Error("the Nix client version is too old");
|
||||||
|
|
||||||
auto tunnelLogger = new TunnelLogger(to, clientVersion);
|
std::unique_ptr<Logger> savedPrevLogger;
|
||||||
auto prevLogger = nix::logger;
|
auto prevLogger = nix::logger.get();
|
||||||
|
auto ownedTunnelLogger = std::make_unique<TunnelLogger>(to, clientVersion);
|
||||||
|
auto tunnelLogger = ownedTunnelLogger.get();
|
||||||
// FIXME
|
// FIXME
|
||||||
if (!recursive)
|
if (!recursive)
|
||||||
logger = tunnelLogger;
|
savedPrevLogger = std::exchange(logger, std::move(ownedTunnelLogger));
|
||||||
|
|
||||||
unsigned int opCount = 0;
|
unsigned int opCount = 0;
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ void setCurActivity(const ActivityId activityId)
|
||||||
curActivity = activityId;
|
curActivity = activityId;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger * logger = makeSimpleLogger(true);
|
std::unique_ptr<Logger> logger = makeSimpleLogger(true);
|
||||||
|
|
||||||
void Logger::warn(const std::string & msg)
|
void Logger::warn(const std::string & msg)
|
||||||
{
|
{
|
||||||
|
@ -129,9 +129,9 @@ void writeToStderr(std::string_view s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger * makeSimpleLogger(bool printBuildLogs)
|
std::unique_ptr<Logger> makeSimpleLogger(bool printBuildLogs)
|
||||||
{
|
{
|
||||||
return new SimpleLogger(printBuildLogs);
|
return std::make_unique<SimpleLogger>(printBuildLogs);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::atomic<uint64_t> nextId{0};
|
std::atomic<uint64_t> nextId{0};
|
||||||
|
@ -159,9 +159,9 @@ void to_json(nlohmann::json & json, std::shared_ptr<Pos> pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct JSONLogger : Logger {
|
struct JSONLogger : Logger {
|
||||||
Logger & prevLogger;
|
std::unique_ptr<Logger> prevLogger;
|
||||||
|
|
||||||
JSONLogger(Logger & prevLogger) : prevLogger(prevLogger) { }
|
JSONLogger(std::unique_ptr<Logger> prevLogger) : prevLogger(std::move(prevLogger)) { }
|
||||||
|
|
||||||
bool isVerbose() override {
|
bool isVerbose() override {
|
||||||
return true;
|
return true;
|
||||||
|
@ -182,7 +182,7 @@ struct JSONLogger : Logger {
|
||||||
|
|
||||||
void write(const nlohmann::json & json)
|
void write(const nlohmann::json & json)
|
||||||
{
|
{
|
||||||
prevLogger.log(lvlError, "@nix " + json.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace));
|
prevLogger->log(lvlError, "@nix " + json.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace));
|
||||||
}
|
}
|
||||||
|
|
||||||
void log(Verbosity lvl, std::string_view s) override
|
void log(Verbosity lvl, std::string_view s) override
|
||||||
|
@ -254,9 +254,9 @@ struct JSONLogger : Logger {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Logger * makeJSONLogger(Logger & prevLogger)
|
std::unique_ptr<Logger> makeJSONLogger(std::unique_ptr<Logger> prevLogger)
|
||||||
{
|
{
|
||||||
return new JSONLogger(prevLogger);
|
return std::make_unique<JSONLogger>(std::move(prevLogger));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Logger::Fields getFields(nlohmann::json & json)
|
static Logger::Fields getFields(nlohmann::json & json)
|
||||||
|
|
|
@ -227,11 +227,11 @@ struct PushActivity
|
||||||
~PushActivity() { setCurActivity(prevAct); }
|
~PushActivity() { setCurActivity(prevAct); }
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Logger * logger;
|
extern std::unique_ptr<Logger> logger;
|
||||||
|
|
||||||
Logger * makeSimpleLogger(bool printBuildLogs = true);
|
std::unique_ptr<Logger> makeSimpleLogger(bool printBuildLogs = true);
|
||||||
|
|
||||||
Logger * makeJSONLogger(Logger & prevLogger);
|
std::unique_ptr<Logger> makeJSONLogger(std::unique_ptr<Logger> prevLogger);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* suppress msgs > this
|
* suppress msgs > this
|
||||||
|
|
|
@ -27,20 +27,17 @@ namespace nix {
|
||||||
};
|
};
|
||||||
|
|
||||||
class CaptureLogging {
|
class CaptureLogging {
|
||||||
Logger * oldLogger;
|
std::unique_ptr<Logger> oldLogger;
|
||||||
std::unique_ptr<CaptureLogger> tempLogger;
|
|
||||||
public:
|
public:
|
||||||
CaptureLogging() : tempLogger(std::make_unique<CaptureLogger>()) {
|
CaptureLogging() : oldLogger(std::exchange(logger, std::make_unique<CaptureLogger>())) {}
|
||||||
oldLogger = logger;
|
|
||||||
logger = tempLogger.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
~CaptureLogging() {
|
~CaptureLogging() {
|
||||||
logger = oldLogger;
|
logger = std::move(oldLogger);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get() const {
|
std::string get() const {
|
||||||
return tempLogger->get();
|
auto captureLogger = dynamic_cast<CaptureLogger *>(logger.get());
|
||||||
|
return captureLogger ? captureLogger->get() : "";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace nix
|
||||||
initGC();
|
initGC();
|
||||||
|
|
||||||
startProgressBar();
|
startProgressBar();
|
||||||
ASSERT_NE(dynamic_cast<ProgressBar *>(logger), nullptr);
|
ASSERT_NE(dynamic_cast<ProgressBar *>(logger.get()), nullptr);
|
||||||
ProgressBar & progressBar = dynamic_cast<ProgressBar &>(*logger);
|
ProgressBar & progressBar = dynamic_cast<ProgressBar &>(*logger);
|
||||||
|
|
||||||
Activity act(
|
Activity act(
|
||||||
|
|
Loading…
Reference in a new issue