CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
InitRootHandlers.cc
Go to the documentation of this file.
2 
15 
16 #include <sys/wait.h>
17 #include <sstream>
18 #include <string.h>
19 
20 #include "TROOT.h"
21 #include "TError.h"
22 #include "TFile.h"
23 #include "TInterpreter.h"
24 #include "TH1.h"
25 #include "TSystem.h"
26 #include "TUnixSystem.h"
27 #include "TTree.h"
28 #include "TVirtualStreamerInfo.h"
29 
30 #include "TThread.h"
31 #include "TClassTable.h"
32 
33 namespace edm {
34  namespace service {
35  int cmssw_stacktrace(void *);
36  }
37 }
38 
39 namespace {
40  enum class SeverityLevel {
41  kInfo,
42  kWarning,
43  kError,
44  kSysError,
45  kFatal
46  };
47 
48  static thread_local bool s_ignoreWarnings = false;
49 
50  static bool s_ignoreEverything = false;
51 
52  void RootErrorHandlerImpl(int level, char const* location, char const* message) {
53 
54  bool die = false;
55 
56  // Translate ROOT severity level to MessageLogger severity level
57 
58  SeverityLevel el_severity = SeverityLevel::kInfo;
59 
60  if (level >= kFatal) {
61  el_severity = SeverityLevel::kFatal;
62  } else if (level >= kSysError) {
63  el_severity = SeverityLevel::kSysError;
64  } else if (level >= kError) {
65  el_severity = SeverityLevel::kError;
66  } else if (level >= kWarning) {
67  el_severity = s_ignoreWarnings ? SeverityLevel::kInfo : SeverityLevel::kWarning;
68  }
69 
70  if(s_ignoreEverything) {
71  el_severity = SeverityLevel::kInfo;
72  }
73 
74  // Adapt C-strings to std::strings
75  // Arrange to report the error location as furnished by Root
76 
77  std::string el_location = "@SUB=?";
78  if (location != 0) el_location = std::string("@SUB=")+std::string(location);
79 
80  std::string el_message = "?";
81  if (message != 0) el_message = message;
82 
83  // Try to create a meaningful id string using knowledge of ROOT error messages
84  //
85  // id == "ROOT-ClassName" where ClassName is the affected class
86  // else "ROOT/ClassName" where ClassName is the error-declaring class
87  // else "ROOT"
88 
89  std::string el_identifier = "ROOT";
90 
91  std::string precursor("class ");
92  size_t index1 = el_message.find(precursor);
93  if (index1 != std::string::npos) {
94  size_t index2 = index1 + precursor.length();
95  size_t index3 = el_message.find_first_of(" :", index2);
96  if (index3 != std::string::npos) {
97  size_t substrlen = index3-index2;
98  el_identifier += "-";
99  el_identifier += el_message.substr(index2,substrlen);
100  }
101  } else {
102  index1 = el_location.find("::");
103  if (index1 != std::string::npos) {
104  el_identifier += "/";
105  el_identifier += el_location.substr(0, index1);
106  }
107  }
108 
109  // Intercept some messages and upgrade the severity
110 
111  if ((el_location.find("TBranchElement::Fill") != std::string::npos)
112  && (el_message.find("fill branch") != std::string::npos)
113  && (el_message.find("address") != std::string::npos)
114  && (el_message.find("not set") != std::string::npos)) {
115  el_severity = SeverityLevel::kFatal;
116  }
117 
118  if ((el_message.find("Tree branches") != std::string::npos)
119  && (el_message.find("different numbers of entries") != std::string::npos)) {
120  el_severity = SeverityLevel::kFatal;
121  }
122 
123 
124  // Intercept some messages and downgrade the severity
125 
126  if ((el_message.find("no dictionary for class") != std::string::npos) ||
127  (el_message.find("already in TClassTable") != std::string::npos) ||
128  (el_message.find("matrix not positive definite") != std::string::npos) ||
129  (el_message.find("not a TStreamerInfo object") != std::string::npos) ||
130  (el_message.find("Problems declaring payload") != std::string::npos) ||
131  (el_message.find("Announced number of args different from the real number of argument passed") != std::string::npos) || // Always printed if gDebug>0 - regardless of whether warning message is real.
132  (el_location.find("Fit") != std::string::npos) ||
133  (el_location.find("TDecompChol::Solve") != std::string::npos) ||
134  (el_location.find("THistPainter::PaintInit") != std::string::npos) ||
135  (el_location.find("TUnixSystem::SetDisplay") != std::string::npos) ||
136  (el_location.find("TGClient::GetFontByName") != std::string::npos) ||
137  (el_message.find("nbins is <=0 - set to nbins = 1") != std::string::npos) ||
138  (el_message.find("nbinsy is <=0 - set to nbinsy = 1") != std::string::npos) ||
139  (level < kError and
140  (el_location.find("CINTTypedefBuilder::Setup")!= std::string::npos) and
141  (el_message.find("possible entries are in use!") != std::string::npos))) {
142  el_severity = SeverityLevel::kInfo;
143  }
144 
145  if (el_severity == SeverityLevel::kInfo) {
146  // Don't throw if the message is just informational.
147  die = false;
148  } else {
149  die = true;
150  }
151 
152  // Feed the message to the MessageLogger and let it choose to suppress or not.
153 
154  // Root has declared a fatal error. Throw an EDMException unless the
155  // message corresponds to a pending signal. In that case, do not throw
156  // but let the OS deal with the signal in the usual way.
157  if (die && (el_location != std::string("@SUB=TUnixSystem::DispatchSignals"))) {
158  std::ostringstream sstr;
159  sstr << "Fatal Root Error: " << el_location << "\n" << el_message << '\n';
160  edm::Exception except(edm::errors::FatalRootError, sstr.str());
161  except.addAdditionalInfo(except.message());
162  except.clearMessage();
163  throw except;
164 
165  }
166 
167  // Typically, we get here only for informational messages,
168  // but we leave the other code in just in case we change
169  // the criteria for throwing.
170  if (el_severity == SeverityLevel::kFatal) {
171  edm::LogError("Root_Fatal") << el_location << el_message;
172  } else if (el_severity == SeverityLevel::kSysError) {
173  edm::LogError("Root_Severe") << el_location << el_message;
174  } else if (el_severity == SeverityLevel::kError) {
175  edm::LogError("Root_Error") << el_location << el_message;
176  } else if (el_severity == SeverityLevel::kWarning) {
177  edm::LogWarning("Root_Warning") << el_location << el_message ;
178  } else if (el_severity == SeverityLevel::kInfo) {
179  edm::LogInfo("Root_Information") << el_location << el_message ;
180  }
181  }
182 
183  void RootErrorHandler(int level, bool, char const* location, char const* message) {
184  RootErrorHandlerImpl(level, location, message);
185  }
186 
187  extern "C" {
188 
189  static int full_cerr_write(const char *text)
190  {
191  const char *buffer = text;
192  size_t count = strlen(text);
193  ssize_t written = 0;
194  while (count)
195  {
196  written = write(2, buffer, count);
197  if (written == -1)
198  {
199  if (errno == EINTR) {continue;}
200  else {return -errno;}
201  }
202  count -= written;
203  buffer += written;
204  }
205  return 0;
206  }
207 
208  void sig_dostack_then_abort(int sig, siginfo_t*, void*) {
209 
210  const char* signalname = "unknown";
211  switch (sig) {
212  case SIGBUS:
213  signalname = "bus error";
214  break;
215  case SIGSEGV:
216  signalname = "segmentation violation";
217  break;
218  case SIGILL:
219  signalname = "illegal instruction";
220  default:
221  break;
222  }
223  full_cerr_write("\n\nA fatal system signal has occurred: ");
224  full_cerr_write(signalname);
225  full_cerr_write("\nThe following is the call stack containing the origin of the signal.\n"
226  "NOTE:The first few functions on the stack are artifacts of processing the signal and can be ignored\n\n");
227 
228  char child_stack[4*1024];
229  char *child_stack_ptr = child_stack + 4*1024;
230  // On Linux, we currently use jemalloc. This registers pthread_atfork handlers; these
231  // handlers are *not* async-signal safe. Hence, a deadlock is possible if we invoke
232  // fork() from our signal handlers. Accordingly, we use clone (not POSIX, but AS-safe)
233  // as that is closer to the 'raw metal' syscall and avoids pthread_atfork handlers.
234  int pid =
235 #ifdef __linux__
236  clone(edm::service::cmssw_stacktrace, child_stack_ptr, CLONE_VFORK|CLONE_VM|CLONE_FS|SIGCHLD, nullptr);
237 #else
238  fork();
239  if (child_stack_ptr) {} // Suppress 'unused variable' warning on non-Linux
240  if (pid == 0) {edm::service::cmssw_stacktrace(nullptr); ::abort();}
241 #endif
242  if (pid == -1)
243  {
244  full_cerr_write("(Attempt to perform stack dump failed.)\n");
245  }
246  else
247  {
248  int status;
249  if (waitpid(pid, &status, 0) == -1)
250  {
251  full_cerr_write("(Failed to wait on stack dump output.)\n");
252  }
253  }
254 
255  full_cerr_write("\nA fatal system signal has occurred: ");
256  full_cerr_write(signalname);
257  full_cerr_write("\n");
258  ::abort();
259  }
260 
261  void sig_abort(int sig, siginfo_t*, void*) {
262  ::abort();
263  }
264  }
265 } // end of unnamed namespace
266 
267 namespace edm {
268  namespace service {
269 
270  int cmssw_stacktrace(void * /*arg*/)
271  {
273  execv("/bin/sh", argv);
274  ::abort();
275  return 1;
276  }
277 
278  static char pstackName[] = "(CMSSW stack trace helper)";
279  static char dashC[] = "-c";
282 
284  : RootHandlers(),
285  unloadSigHandler_(pset.getUntrackedParameter<bool> ("UnloadRootSigHandler")),
286  resetErrHandler_(pset.getUntrackedParameter<bool> ("ResetRootErrHandler")),
287  loadAllDictionaries_(pset.getUntrackedParameter<bool>("LoadAllDictionaries")),
288  autoLibraryLoader_(loadAllDictionaries_ or pset.getUntrackedParameter<bool> ("AutoLibraryLoader"))
289  {
290 
291  if(unloadSigHandler_) {
292  // Deactivate all the Root signal handlers and restore the system defaults
293  gSystem->ResetSignal(kSigChild);
294  gSystem->ResetSignal(kSigBus);
295  gSystem->ResetSignal(kSigSegmentationViolation);
296  gSystem->ResetSignal(kSigIllegalInstruction);
297  gSystem->ResetSignal(kSigSystem);
298  gSystem->ResetSignal(kSigPipe);
299  gSystem->ResetSignal(kSigAlarm);
300  gSystem->ResetSignal(kSigUrgent);
301  gSystem->ResetSignal(kSigFloatingException);
302  gSystem->ResetSignal(kSigWindowChanged);
303  } else if(pset.getUntrackedParameter<bool>("AbortOnSignal")){
304  cachePidInfo();
305 
306  //NOTE: ROOT can also be told to abort on these kinds of problems BUT
307  // it requires an TApplication to be instantiated which causes problems
308  gSystem->ResetSignal(kSigBus);
309  gSystem->ResetSignal(kSigSegmentationViolation);
310  gSystem->ResetSignal(kSigIllegalInstruction);
311  installCustomHandler(SIGBUS,sig_dostack_then_abort);
312  sigBusHandler_ = std::shared_ptr<const void>(nullptr,[](void*) {
313  installCustomHandler(SIGBUS,sig_abort);
314  });
315  installCustomHandler(SIGSEGV,sig_dostack_then_abort);
316  sigSegvHandler_ = std::shared_ptr<const void>(nullptr,[](void*) {
317  installCustomHandler(SIGSEGV,sig_abort);
318  });
319  installCustomHandler(SIGILL,sig_dostack_then_abort);
320  sigIllHandler_ = std::shared_ptr<const void>(nullptr,[](void*) {
321  installCustomHandler(SIGILL,sig_abort);
322  });
324  }
325 
326  if(resetErrHandler_) {
327 
328  // Replace the Root error handler with one that uses the MessageLogger
329  SetErrorHandler(RootErrorHandler);
330  }
331 
332  // Enable automatic Root library loading.
333  if(autoLibraryLoader_) {
334  gInterpreter->SetClassAutoloading(1);
335  }
336 
337  // Set ROOT parameters.
338  TTree::SetMaxTreeSize(kMaxLong64);
339  TH1::AddDirectory(kFALSE);
340  //G__SetCatchException(0);
341 
342  // Set custom streamers
344 
345  // Load the library containing dictionaries for std:: classes, if not already loaded.
346  if (!hasDictionary(typeid(std::vector<std::vector<unsigned int> >))) {
347  edmplugin::PluginCapabilities::get()->load(dictionaryPlugInPrefix() + "std::vector<std::vector<unsigned int> >");
348  }
349 
350  int debugLevel = pset.getUntrackedParameter<int>("DebugLevel");
351  if(debugLevel >0) {
352  gDebug = debugLevel;
353  }
354  }
355 
357  // close all open ROOT files
358  TIter iter(gROOT->GetListOfFiles());
359  TObject *obj = nullptr;
360  while(nullptr != (obj = iter.Next())) {
361  TFile* f = dynamic_cast<TFile*>(obj);
362  if(f) {
363  // We get a new iterator each time,
364  // because closing a file can invalidate the iterator
365  f->Close();
366  iter = TIter(gROOT->GetListOfFiles());
367  }
368  }
369  }
370 
372  //Tell Root we want to be multi-threaded
373  TThread::Initialize();
374  //When threading, also have to keep ROOT from logging all TObjects into a list
375  TObject::SetObjectStat(false);
376 
377  //Have to avoid having Streamers modify themselves after they have been used
378  TVirtualStreamerInfo::Optimize(false);
379  }
380 
382  static thread_local TThread guard;
383  }
384 
387  desc.setComment("Centralized interface to ROOT.");
388  desc.addUntracked<bool>("UnloadRootSigHandler", false)
389  ->setComment("If True, signals are handled by this service, rather than by ROOT.");
390  desc.addUntracked<bool>("ResetRootErrHandler", true)
391  ->setComment("If True, ROOT messages (e.g. errors, warnings) are handled by this service, rather than by ROOT.");
392  desc.addUntracked<bool>("AutoLibraryLoader", true)
393  ->setComment("If True, enables automatic loading of data dictionaries.");
394  desc.addUntracked<bool>("LoadAllDictionaries",false)
395  ->setComment("If True, loads all ROOT dictionaries.");
396  desc.addUntracked<bool>("AbortOnSignal",true)
397  ->setComment("If True, do an abort when a signal occurs that causes a crash. If False, ROOT will do an exit which attempts to do a clean shutdown.");
398  desc.addUntracked<int>("DebugLevel",0)
399  ->setComment("Sets ROOT's gDebug value.");
400  descriptions.add("InitRootHandlers", desc);
401  }
402 
403  char *const *
405  return pstackArgv_;
406  }
407 
408  void
410  s_ignoreWarnings =false;
411  }
412 
413  void
415  s_ignoreWarnings = true;
416  }
417 
418  void
420  {
421  if (snprintf(pidString_, pidStringLength_-1, "gdb -quiet -p %d 2>&1 <<EOF |\n"
422  "set width 0\n"
423  "set height 0\n"
424  "set pagination no\n"
425  "thread apply all bt\n"
426  "EOF\n"
427  "/bin/sed -n -e 's/^\\((gdb) \\)*//' -e '/^#/p' -e '/^Thread/p'", getpid()) >= pidStringLength_)
428  {
429  std::ostringstream sstr;
430  sstr << "Unable to pre-allocate stacktrace handler information";
431  edm::Exception except(edm::errors::OtherCMS, sstr.str());
432  throw except;
433  }
434  }
435 
436  } // end of namespace service
437 } // end of namespace edm
T getUntrackedParameter(std::string const &, T const &) const
virtual void enableWarnings_() override
static char *const pstackArgv_[]
ParameterDescriptionBase * addUntracked(U const &iLabel, T const &value)
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e< void, edm::EventIDconst &, edm::Timestampconst & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Definition: Activities.doc:12
void setRefCoreStreamer(bool resetAll=false)
std::string const & dictionaryPlugInPrefix()
void installCustomHandler(int signum, CFUNC func)
std::shared_ptr< const void > sigSegvHandler_
std::shared_ptr< const void > sigBusHandler_
void cachePidInfoHandler(unsigned int, unsigned int)
void setComment(std::string const &value)
static char pidString_[pidStringLength_]
static char *const * getPstackArgv()
std::shared_ptr< const void > sigIllHandler_
virtual void initializeThisThreadForUse() override
virtual void ignoreWarnings_() override
void addAdditionalInfo(std::string const &info)
Definition: Exception.cc:235
static PluginCapabilities * get()
double f[11][100]
tuple text
Definition: runonSM.py:42
int cmssw_stacktrace(void *)
static char pstackName[]
InitRootHandlers(ParameterSet const &pset, ActivityRegistry &iReg)
tuple pid
Definition: sysUtil.py:22
void add(std::string const &label, ParameterSetDescription const &psetDescription)
TEveGeoShape * clone(const TEveElement *element, TEveElement *parent)
Definition: eve_macros.cc:135
void watchPostForkReacquireResources(PostForkReacquireResources::slot_type const &iSlot)
virtual void willBeUsingThreads() override
static char dashC[]
static void fillDescriptions(ConfigurationDescriptions &descriptions)
SeverityLevel
bool hasDictionary(std::type_info const &)
tuple level
Definition: testEve_cfg.py:34
void load(const std::string &iName)
tuple status
Definition: ntuplemaker.py:245