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_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 
259  // For these three known cases, re-raise the signal so get the correct
260  // exit code.
261  if ((sig == SIGILL) || (sig == SIGSEGV) || (sig == SIGBUS))
262  {
263  signal(sig, SIG_DFL);
264  raise(sig);
265  }
266  ::abort();
267  }
268 
269  void sig_abort(int sig, siginfo_t*, void*) {
270  ::abort();
271  }
272  }
273 } // end of unnamed namespace
274 
275 namespace edm {
276  namespace service {
277 
278  int cmssw_stacktrace(void * /*arg*/)
279  {
281  execv("/bin/sh", argv);
282  ::abort();
283  return 1;
284  }
285 
286  static char pstackName[] = "(CMSSW stack trace helper)";
287  static char dashC[] = "-c";
290 
292  : RootHandlers(),
293  unloadSigHandler_(pset.getUntrackedParameter<bool> ("UnloadRootSigHandler")),
294  resetErrHandler_(pset.getUntrackedParameter<bool> ("ResetRootErrHandler")),
295  loadAllDictionaries_(pset.getUntrackedParameter<bool>("LoadAllDictionaries")),
296  autoLibraryLoader_(loadAllDictionaries_ or pset.getUntrackedParameter<bool> ("AutoLibraryLoader"))
297  {
298 
299  if(unloadSigHandler_) {
300  // Deactivate all the Root signal handlers and restore the system defaults
301  gSystem->ResetSignal(kSigChild);
302  gSystem->ResetSignal(kSigBus);
303  gSystem->ResetSignal(kSigSegmentationViolation);
304  gSystem->ResetSignal(kSigIllegalInstruction);
305  gSystem->ResetSignal(kSigSystem);
306  gSystem->ResetSignal(kSigPipe);
307  gSystem->ResetSignal(kSigAlarm);
308  gSystem->ResetSignal(kSigUrgent);
309  gSystem->ResetSignal(kSigFloatingException);
310  gSystem->ResetSignal(kSigWindowChanged);
311  } else if(pset.getUntrackedParameter<bool>("AbortOnSignal")){
312  cachePidInfo();
313 
314  //NOTE: ROOT can also be told to abort on these kinds of problems BUT
315  // it requires an TApplication to be instantiated which causes problems
316  gSystem->ResetSignal(kSigBus);
317  gSystem->ResetSignal(kSigSegmentationViolation);
318  gSystem->ResetSignal(kSigIllegalInstruction);
319  installCustomHandler(SIGBUS,sig_dostack_then_abort);
320  sigBusHandler_ = std::shared_ptr<const void>(nullptr,[](void*) {
321  installCustomHandler(SIGBUS,sig_abort);
322  });
323  installCustomHandler(SIGSEGV,sig_dostack_then_abort);
324  sigSegvHandler_ = std::shared_ptr<const void>(nullptr,[](void*) {
325  installCustomHandler(SIGSEGV,sig_abort);
326  });
327  installCustomHandler(SIGILL,sig_dostack_then_abort);
328  sigIllHandler_ = std::shared_ptr<const void>(nullptr,[](void*) {
329  installCustomHandler(SIGILL,sig_abort);
330  });
332  }
333 
334  if(resetErrHandler_) {
335 
336  // Replace the Root error handler with one that uses the MessageLogger
337  SetErrorHandler(RootErrorHandler);
338  }
339 
340  // Enable automatic Root library loading.
341  if(autoLibraryLoader_) {
342  gInterpreter->SetClassAutoloading(1);
343  }
344 
345  // Set ROOT parameters.
346  TTree::SetMaxTreeSize(kMaxLong64);
347  TH1::AddDirectory(kFALSE);
348  //G__SetCatchException(0);
349 
350  // Set custom streamers
352 
353  // Load the library containing dictionaries for std:: classes, if not already loaded.
354  if (!hasDictionary(typeid(std::vector<std::vector<unsigned int> >))) {
355  edmplugin::PluginCapabilities::get()->load(dictionaryPlugInPrefix() + "std::vector<std::vector<unsigned int> >");
356  }
357 
358  int debugLevel = pset.getUntrackedParameter<int>("DebugLevel");
359  if(debugLevel >0) {
360  gDebug = debugLevel;
361  }
362  }
363 
365  // close all open ROOT files
366  TIter iter(gROOT->GetListOfFiles());
367  TObject *obj = nullptr;
368  while(nullptr != (obj = iter.Next())) {
369  TFile* f = dynamic_cast<TFile*>(obj);
370  if(f) {
371  // We get a new iterator each time,
372  // because closing a file can invalidate the iterator
373  f->Close();
374  iter = TIter(gROOT->GetListOfFiles());
375  }
376  }
377  }
378 
380  //Tell Root we want to be multi-threaded
381  TThread::Initialize();
382  //When threading, also have to keep ROOT from logging all TObjects into a list
383  TObject::SetObjectStat(false);
384 
385  //Have to avoid having Streamers modify themselves after they have been used
386  TVirtualStreamerInfo::Optimize(false);
387  }
388 
390  static thread_local TThread guard;
391  }
392 
395  desc.setComment("Centralized interface to ROOT.");
396  desc.addUntracked<bool>("UnloadRootSigHandler", false)
397  ->setComment("If True, signals are handled by this service, rather than by ROOT.");
398  desc.addUntracked<bool>("ResetRootErrHandler", true)
399  ->setComment("If True, ROOT messages (e.g. errors, warnings) are handled by this service, rather than by ROOT.");
400  desc.addUntracked<bool>("AutoLibraryLoader", true)
401  ->setComment("If True, enables automatic loading of data dictionaries.");
402  desc.addUntracked<bool>("LoadAllDictionaries",false)
403  ->setComment("If True, loads all ROOT dictionaries.");
404  desc.addUntracked<bool>("AbortOnSignal",true)
405  ->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.");
406  desc.addUntracked<int>("DebugLevel",0)
407  ->setComment("Sets ROOT's gDebug value.");
408  descriptions.add("InitRootHandlers", desc);
409  }
410 
411  char *const *
413  return pstackArgv_;
414  }
415 
416  void
418  s_ignoreWarnings =false;
419  }
420 
421  void
423  s_ignoreWarnings = true;
424  }
425 
426  void
428  {
429  if (snprintf(pidString_, pidStringLength_-1, "gdb -quiet -p %d 2>&1 <<EOF |\n"
430  "set width 0\n"
431  "set height 0\n"
432  "set pagination no\n"
433  "thread apply all bt\n"
434  "EOF\n"
435  "/bin/sed -n -e 's/^\\((gdb) \\)*//' -e '/^#/p' -e '/^Thread/p'", getpid()) >= pidStringLength_)
436  {
437  std::ostringstream sstr;
438  sstr << "Unable to pre-allocate stacktrace handler information";
439  edm::Exception except(edm::errors::OtherCMS, sstr.str());
440  throw except;
441  }
442  }
443 
444  } // end of namespace service
445 } // 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