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 volatile bool gbWatchdogFiring = false;
31 osl::Condition* gpWatchdogExit = nullptr;
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", "Watchdog triggered: hard disable " << Zone::name());
60 #ifdef DBG_UTIL
61  std::abort();
62 #else
63  Zone::hardDisable();
64  gbWatchdogFiring = false;
65 #endif
66  }
67  bFired = true;
68 
69  // we can hang using VCL in the abort handling -> be impatient
70  if (bAbortFired)
71  {
72  SAL_WARN("vcl.watchdog", "Watchdog gave up: hard exiting " << Zone::name());
73  _Exit(1);
74  }
75  }
76 
77  // Not making even more progress
78  if (nUnchanged >= aTimingValues.mnAbortAfter)
79  {
80  if (!bAbortFired)
81  {
82  SAL_WARN("vcl.watchdog", "Watchdog gave up: aborting " << Zone::name());
83  gbWatchdogFiring = true;
84  std::abort();
85  }
86  // coverity[dead_error_line] - we might have caught SIGABRT and failed to exit yet
87  bAbortFired = true;
88  }
89  }
90  else
91  {
92  nUnchanged = 0;
93  }
94  }
95 };
96 
97 } // namespace
98 
100  : salhelper::Thread("Crash Watchdog")
101 {
102 }
103 
105 {
106  TimeValue aQuarterSecond(0, 1000 * 1000 * 1000 * 0.25);
107  do
108  {
109 #if HAVE_FEATURE_OPENGL
110  WatchdogHelper<OpenGLZone>::setLastEnters();
111 #endif
112 #if HAVE_FEATURE_SKIA
113  WatchdogHelper<SkiaZone>::setLastEnters();
114 #endif
115 
116  gpWatchdogExit->wait(&aQuarterSecond);
117 
118 #if defined HAVE_VALGRIND_HEADERS
119  if (RUNNING_ON_VALGRIND)
120  continue;
121 #endif
122 #if defined DBG_UTIL
124  continue;
125 #endif
126 
127 #if HAVE_FEATURE_OPENGL
128  WatchdogHelper<OpenGLZone>::check();
129 #endif
130 #if HAVE_FEATURE_SKIA
131  WatchdogHelper<SkiaZone>::check();
132 #endif
133 
134  } while (!gpWatchdogExit->check());
135 }
136 
138 {
139  if (gxWatchdog != nullptr)
140  return; // already running
141  if (getenv("SAL_DISABLE_WATCHDOG"))
142  return;
143  gpWatchdogExit = new osl::Condition();
144  gxWatchdog.set(new WatchdogThread());
145  gxWatchdog->launch();
146 }
147 
149 {
150  if (gbWatchdogFiring)
151  return; // in watchdog thread
152 
153  if (gpWatchdogExit)
154  gpWatchdogExit->set();
155 
156  if (gxWatchdog.is())
157  {
158  gxWatchdog->join();
159  gxWatchdog.clear();
160  }
161 
162  delete gpWatchdogExit;
163  gpWatchdogExit = nullptr;
164 }
165 
166 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static void stop()
Definition: watchdog.cxx:148
virtual void execute() override
Definition: watchdog.cxx:104
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:137
#define SAL_WARN(area, stream)
bool isDebuggerAttached()