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 
14 
15 #include <sstream>
16 #include <string.h>
17 
18 #include "TROOT.h"
19 #include "TError.h"
20 #include "TFile.h"
21 #include "TInterpreter.h"
22 #include "TH1.h"
23 #include "TSystem.h"
24 #include "TUnixSystem.h"
25 #include "TTree.h"
26 #include "TVirtualStreamerInfo.h"
27 
28 #include "TThread.h"
29 #include "TClassTable.h"
30 
31 namespace {
32  enum class SeverityLevel {
33  kInfo,
34  kWarning,
35  kError,
36  kSysError,
37  kFatal
38  };
39 
40  static thread_local bool s_ignoreWarnings = false;
41 
42  static bool s_ignoreEverything = false;
43 
44  void RootErrorHandlerImpl(int level, char const* location, char const* message) {
45 
46  bool die = false;
47 
48  // Translate ROOT severity level to MessageLogger severity level
49 
50  SeverityLevel el_severity = SeverityLevel::kInfo;
51 
52  if (level >= kFatal) {
53  el_severity = SeverityLevel::kFatal;
54  } else if (level >= kSysError) {
55  el_severity = SeverityLevel::kSysError;
56  } else if (level >= kError) {
57  el_severity = SeverityLevel::kError;
58  } else if (level >= kWarning) {
59  el_severity = s_ignoreWarnings ? SeverityLevel::kInfo : SeverityLevel::kWarning;
60  }
61 
62  if(s_ignoreEverything) {
63  el_severity = SeverityLevel::kInfo;
64  }
65 
66  // Adapt C-strings to std::strings
67  // Arrange to report the error location as furnished by Root
68 
69  std::string el_location = "@SUB=?";
70  if (location != 0) el_location = std::string("@SUB=")+std::string(location);
71 
72  std::string el_message = "?";
73  if (message != 0) el_message = message;
74 
75  // Try to create a meaningful id string using knowledge of ROOT error messages
76  //
77  // id == "ROOT-ClassName" where ClassName is the affected class
78  // else "ROOT/ClassName" where ClassName is the error-declaring class
79  // else "ROOT"
80 
81  std::string el_identifier = "ROOT";
82 
83  std::string precursor("class ");
84  size_t index1 = el_message.find(precursor);
85  if (index1 != std::string::npos) {
86  size_t index2 = index1 + precursor.length();
87  size_t index3 = el_message.find_first_of(" :", index2);
88  if (index3 != std::string::npos) {
89  size_t substrlen = index3-index2;
90  el_identifier += "-";
91  el_identifier += el_message.substr(index2,substrlen);
92  }
93  } else {
94  index1 = el_location.find("::");
95  if (index1 != std::string::npos) {
96  el_identifier += "/";
97  el_identifier += el_location.substr(0, index1);
98  }
99  }
100 
101  // Intercept some messages and upgrade the severity
102 
103  if ((el_location.find("TBranchElement::Fill") != std::string::npos)
104  && (el_message.find("fill branch") != std::string::npos)
105  && (el_message.find("address") != std::string::npos)
106  && (el_message.find("not set") != std::string::npos)) {
107  el_severity = SeverityLevel::kFatal;
108  }
109 
110  if ((el_message.find("Tree branches") != std::string::npos)
111  && (el_message.find("different numbers of entries") != std::string::npos)) {
112  el_severity = SeverityLevel::kFatal;
113  }
114 
115 
116  // Intercept some messages and downgrade the severity
117 
118  if ((el_message.find("no dictionary for class") != std::string::npos) ||
119  (el_message.find("already in TClassTable") != std::string::npos) ||
120  (el_message.find("matrix not positive definite") != std::string::npos) ||
121  (el_message.find("not a TStreamerInfo object") != std::string::npos) ||
122  (el_message.find("Problems declaring payload") != std::string::npos) ||
123  (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.
124  (el_location.find("Fit") != std::string::npos) ||
125  (el_location.find("TDecompChol::Solve") != std::string::npos) ||
126  (el_location.find("THistPainter::PaintInit") != std::string::npos) ||
127  (el_location.find("TUnixSystem::SetDisplay") != std::string::npos) ||
128  (el_location.find("TGClient::GetFontByName") != std::string::npos) ||
129  (el_message.find("nbins is <=0 - set to nbins = 1") != std::string::npos) ||
130  (el_message.find("nbinsy is <=0 - set to nbinsy = 1") != std::string::npos) ||
131  (level < kError and
132  (el_location.find("CINTTypedefBuilder::Setup")!= std::string::npos) and
133  (el_message.find("possible entries are in use!") != std::string::npos))) {
134  el_severity = SeverityLevel::kInfo;
135  }
136 
137  if (el_severity == SeverityLevel::kInfo) {
138  // Don't throw if the message is just informational.
139  die = false;
140  } else {
141  die = true;
142  }
143 
144  // Feed the message to the MessageLogger and let it choose to suppress or not.
145 
146  // Root has declared a fatal error. Throw an EDMException unless the
147  // message corresponds to a pending signal. In that case, do not throw
148  // but let the OS deal with the signal in the usual way.
149  if (die && (el_location != std::string("@SUB=TUnixSystem::DispatchSignals"))) {
150  std::ostringstream sstr;
151  sstr << "Fatal Root Error: " << el_location << "\n" << el_message << '\n';
152  edm::Exception except(edm::errors::FatalRootError, sstr.str());
153  except.addAdditionalInfo(except.message());
154  except.clearMessage();
155  throw except;
156 
157  }
158 
159  // Typically, we get here only for informational messages,
160  // but we leave the other code in just in case we change
161  // the criteria for throwing.
162  if (el_severity == SeverityLevel::kFatal) {
163  edm::LogError("Root_Fatal") << el_location << el_message;
164  } else if (el_severity == SeverityLevel::kSysError) {
165  edm::LogError("Root_Severe") << el_location << el_message;
166  } else if (el_severity == SeverityLevel::kError) {
167  edm::LogError("Root_Error") << el_location << el_message;
168  } else if (el_severity == SeverityLevel::kWarning) {
169  edm::LogWarning("Root_Warning") << el_location << el_message ;
170  } else if (el_severity == SeverityLevel::kInfo) {
171  edm::LogInfo("Root_Information") << el_location << el_message ;
172  }
173  }
174 
175  void RootErrorHandler(int level, bool, char const* location, char const* message) {
176  RootErrorHandlerImpl(level, location, message);
177  }
178 
179  extern "C" {
180  void sig_dostack_then_abort(int sig,siginfo_t*,void*) {
181  if (gSystem) {
182  const char* signalname = "unknown";
183  switch (sig) {
184  case SIGBUS:
185  signalname = "bus error";
186  break;
187  case SIGSEGV:
188  signalname = "segmentation violation";
189  break;
190  case SIGILL:
191  signalname = "illegal instruction";
192  default:
193  break;
194  }
195  edm::LogError("FatalSystemSignal")<<"A fatal system signal has occurred: "<<signalname;
196  std::cerr<< "\n\nA fatal system signal has occurred: "<<signalname<<"\n"
197  <<"The following is the call stack containing the origin of the signal.\n"
198  <<"NOTE:The first few functions on the stack are artifacts of processing the signal and can be ignored\n\n";
199 
200  gSystem->StackTrace();
201  std::cerr<<"\nA fatal system signal has occurred: "<<signalname<<"\n";
202  }
203  ::abort();
204  }
205 
206  void sig_abort(int sig, siginfo_t*, void*) {
207  ::abort();
208  }
209  }
210 } // end of unnamed namespace
211 
212 namespace edm {
213  namespace service {
215  : RootHandlers(),
216  unloadSigHandler_(pset.getUntrackedParameter<bool> ("UnloadRootSigHandler")),
217  resetErrHandler_(pset.getUntrackedParameter<bool> ("ResetRootErrHandler")),
218  loadAllDictionaries_(pset.getUntrackedParameter<bool>("LoadAllDictionaries")),
219  autoLibraryLoader_(loadAllDictionaries_ or pset.getUntrackedParameter<bool> ("AutoLibraryLoader"))
220  {
221 
222  if(unloadSigHandler_) {
223  // Deactivate all the Root signal handlers and restore the system defaults
224  gSystem->ResetSignal(kSigChild);
225  gSystem->ResetSignal(kSigBus);
226  gSystem->ResetSignal(kSigSegmentationViolation);
227  gSystem->ResetSignal(kSigIllegalInstruction);
228  gSystem->ResetSignal(kSigSystem);
229  gSystem->ResetSignal(kSigPipe);
230  gSystem->ResetSignal(kSigAlarm);
231  gSystem->ResetSignal(kSigUrgent);
232  gSystem->ResetSignal(kSigFloatingException);
233  gSystem->ResetSignal(kSigWindowChanged);
234  } else if(pset.getUntrackedParameter<bool>("AbortOnSignal")){
235  //NOTE: ROOT can also be told to abort on these kinds of problems BUT
236  // it requires an TApplication to be instantiated which causes problems
237  gSystem->ResetSignal(kSigBus);
238  gSystem->ResetSignal(kSigSegmentationViolation);
239  gSystem->ResetSignal(kSigIllegalInstruction);
240  installCustomHandler(SIGBUS,sig_dostack_then_abort);
241  sigBusHandler_ = std::shared_ptr<const void>(nullptr,[](void*) {
242  installCustomHandler(SIGBUS,sig_abort);
243  });
244  installCustomHandler(SIGSEGV,sig_dostack_then_abort);
245  sigSegvHandler_ = std::shared_ptr<const void>(nullptr,[](void*) {
246  installCustomHandler(SIGSEGV,sig_abort);
247  });
248  installCustomHandler(SIGILL,sig_dostack_then_abort);
249  sigIllHandler_ = std::shared_ptr<const void>(nullptr,[](void*) {
250  installCustomHandler(SIGILL,sig_abort);
251  });
252  }
253 
254  if(resetErrHandler_) {
255 
256  // Replace the Root error handler with one that uses the MessageLogger
257  SetErrorHandler(RootErrorHandler);
258  }
259 
260  // Enable automatic Root library loading.
261  if(autoLibraryLoader_) {
262  gInterpreter->SetClassAutoloading(1);
263  }
264 
265  // Set ROOT parameters.
266  TTree::SetMaxTreeSize(kMaxLong64);
267  TH1::AddDirectory(kFALSE);
268  //G__SetCatchException(0);
269 
270  // Set custom streamers
272 
273  // Load the library containing dictionaries for std:: classes, if not already loaded.
274  if (!hasDictionary(typeid(std::vector<std::vector<unsigned int> >))) {
275  edmplugin::PluginCapabilities::get()->load(dictionaryPlugInPrefix() + "std::vector<std::vector<unsigned int> >");
276  }
277 
278  int debugLevel = pset.getUntrackedParameter<int>("DebugLevel");
279  if(debugLevel >0) {
280  gDebug = debugLevel;
281  }
282  }
283 
285  // close all open ROOT files
286  TIter iter(gROOT->GetListOfFiles());
287  TObject *obj = nullptr;
288  while(nullptr != (obj = iter.Next())) {
289  TFile* f = dynamic_cast<TFile*>(obj);
290  if(f) {
291  // We get a new iterator each time,
292  // because closing a file can invalidate the iterator
293  f->Close();
294  iter = TIter(gROOT->GetListOfFiles());
295  }
296  }
297  }
298 
300  //Tell Root we want to be multi-threaded
301  TThread::Initialize();
302  //When threading, also have to keep ROOT from logging all TObjects into a list
303  TObject::SetObjectStat(false);
304 
305  //Have to avoid having Streamers modify themselves after they have been used
306  TVirtualStreamerInfo::Optimize(false);
307  }
308 
310  static thread_local TThread guard;
311  }
312 
315  desc.setComment("Centralized interface to ROOT.");
316  desc.addUntracked<bool>("UnloadRootSigHandler", false)
317  ->setComment("If True, signals are handled by this service, rather than by ROOT.");
318  desc.addUntracked<bool>("ResetRootErrHandler", true)
319  ->setComment("If True, ROOT messages (e.g. errors, warnings) are handled by this service, rather than by ROOT.");
320  desc.addUntracked<bool>("AutoLibraryLoader", true)
321  ->setComment("If True, enables automatic loading of data dictionaries.");
322  desc.addUntracked<bool>("LoadAllDictionaries",false)
323  ->setComment("If True, loads all ROOT dictionaries.");
324  desc.addUntracked<bool>("AbortOnSignal",true)
325  ->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.");
326  desc.addUntracked<int>("DebugLevel",0)
327  ->setComment("Sets ROOT's gDebug value.");
328  descriptions.add("InitRootHandlers", desc);
329  }
330 
331  void
333  s_ignoreWarnings =false;
334  }
335 
336  void
338  s_ignoreWarnings = true;
339  }
340 
341  } // end of namespace service
342 } // end of namespace edm
T getUntrackedParameter(std::string const &, T const &) const
virtual void enableWarnings_() override
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 setComment(std::string const &value)
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]
InitRootHandlers(ParameterSet const &pset)
void add(std::string const &label, ParameterSetDescription const &psetDescription)
virtual void willBeUsingThreads() override
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)