/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <watchdog.hxx>
#include <config_features.h>
#include <osl/conditn.hxx>
#include <rtl/ref.hxx>
#include <rtl/string.hxx>
#include <sal/log.hxx>
#include <comphelper/debuggerinfo.hxx>
#include <opengl/zone.hxx>
#include <skia/zone.hxx>
#include <stdlib.h>
#if defined HAVE_VALGRIND_HEADERS
#include <valgrind/memcheck.h>
#endif
#include <atomic>
namespace
{
std::atomic<bool> gbWatchdogFiring = false;
osl::Condition* gpWatchdogExit = nullptr;
rtl::Reference<WatchdogThread> gxWatchdog;
template <typename Zone> struct WatchdogHelper
{
static inline sal_uInt64 nLastEnters = 0;
static inline int nUnchanged = 0; // how many unchanged nEnters
static inline bool bFired = false;
static inline bool bAbortFired = false;
static void setLastEnters() { nLastEnters = Zone::enterCount(); }
static void check()
{
if (Zone::isInZone())
{
const CrashWatchdogTimingsValues& aTimingValues = Zone::getCrashWatchdogTimingsValues();
if (nLastEnters == Zone::enterCount())
nUnchanged++;
else
nUnchanged = 0;
Zone::checkDebug(nUnchanged, aTimingValues);
// Not making progress
if (nUnchanged >= aTimingValues.mnDisableEntries)
{
if (!bFired)
{
gbWatchdogFiring = true;
SAL_WARN("vcl.watchdog", "Watchdog triggered: hard disable " << Zone::name());
#ifdef DBG_UTIL
std::abort();
#else
Zone::hardDisable();
gbWatchdogFiring = false;
#endif
}
bFired = true;
// we can hang using VCL in the abort handling -> be impatient
if (bAbortFired)
{
SAL_WARN("vcl.watchdog", "Watchdog gave up: hard exiting " << Zone::name());
_Exit(1);
}
}
// Not making even more progress
if (nUnchanged >= aTimingValues.mnAbortAfter)
{
if (!bAbortFired)
{
SAL_WARN("vcl.watchdog", "Watchdog gave up: aborting " << Zone::name());
gbWatchdogFiring = true;
std::abort();
}
// coverity[dead_error_line] - we might have caught SIGABRT and failed to exit yet
bAbortFired = true;
}
}
else
{
nUnchanged = 0;
}
}
};
} // namespace
WatchdogThread::WatchdogThread()
: salhelper::Thread("Crash Watchdog")
{
}
void WatchdogThread::execute()
{
TimeValue aQuarterSecond(0, 1000 * 1000 * 1000 * 0.25);
do
{
#if HAVE_FEATURE_OPENGL
WatchdogHelper<OpenGLZone>::setLastEnters();
#endif
#if HAVE_FEATURE_SKIA
WatchdogHelper<SkiaZone>::setLastEnters();
#endif
gpWatchdogExit->wait(&aQuarterSecond);
#if defined HAVE_VALGRIND_HEADERS
if (RUNNING_ON_VALGRIND)
continue;
#endif
#if defined DBG_UTIL
if (comphelper::isDebuggerAttached())
continue;
#endif
#if HAVE_FEATURE_OPENGL
WatchdogHelper<OpenGLZone>::check();
#endif
#if HAVE_FEATURE_SKIA
WatchdogHelper<SkiaZone>::check();
#endif
} while (!gpWatchdogExit->check());
}
void WatchdogThread::start()
{
if (gxWatchdog != nullptr)
return; // already running
if (getenv("SAL_DISABLE_WATCHDOG"))
return;
gpWatchdogExit = new osl::Condition();
gxWatchdog.set(new WatchdogThread());
gxWatchdog->launch();
}
void WatchdogThread::stop()
{
if (gbWatchdogFiring)
return; // in watchdog thread
if (gpWatchdogExit)
gpWatchdogExit->set();
if (gxWatchdog.is())
{
gxWatchdog->join();
gxWatchdog.clear();
}
delete gpWatchdogExit;
gpWatchdogExit = nullptr;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V1048 The 'bAbortFired' variable was assigned the same value.