LibreOffice Module vcl (master)  1
watchdog.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include <watchdog.hxx>
11 
12 #include <config_features.h>
13 
14 #include <osl/conditn.hxx>
15 #include <rtl/ref.hxx>
16 #include <rtl/string.hxx>
17 #include <sal/log.hxx>
19 #include <opengl/zone.hxx>
20 #include <skia/zone.hxx>
21 
22 #include <stdlib.h>
23 
24 #if defined HAVE_VALGRIND_HEADERS
25 #include <valgrind/memcheck.h>
26 #endif
27 
28 namespace
29 {
30 static volatile bool gbWatchdogFiring = false;
31 static osl::Condition* gpWatchdogExit = nullptr;
32 static rtl::Reference<WatchdogThread> gxWatchdog;
33 
34 template <typename Zone> struct WatchdogHelper
35 {
36  static inline sal_uInt64 nLastEnters = 0;
37  static inline int nUnchanged = 0; // how many unchanged nEnters
38  static inline bool bFired = false;
39  static inline bool bAbortFired = false;
40  static void setLastEnters() { nLastEnters = Zone::enterCount(); }
41  static void check()
42  {
43  if (Zone::isInZone())
44  {
45  const CrashWatchdogTimingsValues& aTimingValues = Zone::getCrashWatchdogTimingsValues();
46 
47  if (nLastEnters == Zone::enterCount())
48  nUnchanged++;
49  else
50  nUnchanged = 0;
51  Zone::checkDebug(nUnchanged, aTimingValues);
52 
53  // Not making progress
54  if (nUnchanged >= aTimingValues.mnDisableEntries)
55  {
56  if (!bFired)
57  {
58  gbWatchdogFiring = true;
59  SAL_WARN("vcl.watchdog",
60  OStringLiteral("Watchdog triggered: hard disable ") + Zone::name());
61  Zone::hardDisable();
62  gbWatchdogFiring = false;
63  }
64  bFired = true;
65 
66  // we can hang using VCL in the abort handling -> be impatient
67  if (bAbortFired)
68  {
69  SAL_WARN("vcl.watchdog",
70  OStringLiteral("Watchdog gave up: hard exiting ") + Zone::name());
71  _Exit(1);
72  }
73  }
74 
75  // Not making even more progress
76  if (nUnchanged >= aTimingValues.mnAbortAfter)
77  {
78  if (!bAbortFired)
79  {
80  SAL_WARN("vcl.watchdog",
81  OStringLiteral("Watchdog gave up: aborting ") + Zone::name());
82  gbWatchdogFiring = true;
83  std::abort();
84  }
85  // coverity[dead_error_line] - we might have caught SIGABRT and failed to exit yet
86  bAbortFired = true;
87  }
88  }
89  else
90  {
91  nUnchanged = 0;
92  }
93  }
94 };
95 
96 } // namespace
97 
99  : salhelper::Thread("Crash Watchdog")
100 {
101 }
102 
104 {
105  TimeValue aQuarterSecond(0, 1000 * 1000 * 1000 * 0.25);
106  do
107  {
108 #if HAVE_FEATURE_OPENGL
109  WatchdogHelper<OpenGLZone>::setLastEnters();
110 #endif
111 #if HAVE_FEATURE_SKIA
112  WatchdogHelper<SkiaZone>::setLastEnters();
113 #endif
114 
115  gpWatchdogExit->wait(&aQuarterSecond);
116 
117 #if defined HAVE_VALGRIND_HEADERS
118  if (RUNNING_ON_VALGRIND)
119  continue;
120 #endif
121 #if defined DBG_UTIL
123  continue;
124 #endif
125 
126 #if HAVE_FEATURE_OPENGL
127  WatchdogHelper<OpenGLZone>::check();
128 #endif
129 #if HAVE_FEATURE_SKIA
130  WatchdogHelper<SkiaZone>::check();
131 #endif
132 
133  } while (!gpWatchdogExit->check());
134 }
135 
137 {
138  if (gxWatchdog != nullptr)
139  return; // already running
140  if (getenv("SAL_DISABLE_WATCHDOG"))
141  return;
142  gpWatchdogExit = new osl::Condition();
143  gxWatchdog.set(new WatchdogThread());
144  gxWatchdog->launch();
145 }
146 
148 {
149  if (gbWatchdogFiring)
150  return; // in watchdog thread
151 
152  if (gpWatchdogExit)
153  gpWatchdogExit->set();
154 
155  if (gxWatchdog.is())
156  {
157  gxWatchdog->join();
158  gxWatchdog.clear();
159  }
160 
161  delete gpWatchdogExit;
162  gpWatchdogExit = nullptr;
163 }
164 
165 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static void stop()
Definition: watchdog.cxx:147
virtual void execute() override
Definition: watchdog.cxx:103
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC css::uno::Sequence< css::uno::Reference< css::xml::dom::XElement > > check(dp_misc::DescriptionInfoset const &infoset)
static void start()
Definition: watchdog.cxx:136
#define SAL_WARN(area, stream)
bool isDebuggerAttached()