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_location.find("Fit") != std::string::npos) ||
124  (el_location.find("TDecompChol::Solve") != std::string::npos) ||
125  (el_location.find("THistPainter::PaintInit") != std::string::npos) ||
126  (el_location.find("TUnixSystem::SetDisplay") != std::string::npos) ||
127  (el_location.find("TGClient::GetFontByName") != std::string::npos) ||
128  (el_message.find("nbins is <=0 - set to nbins = 1") != std::string::npos) ||
129  (el_message.find("nbinsy is <=0 - set to nbinsy = 1") != std::string::npos) ||
130  (level < kError and
131  (el_location.find("CINTTypedefBuilder::Setup")!= std::string::npos) and
132  (el_message.find("possible entries are in use!") != std::string::npos))) {
133  el_severity = SeverityLevel::kInfo;
134  }
135 
136  if (el_severity == SeverityLevel::kInfo) {
137  // Don't throw if the message is just informational.
138  die = false;
139  } else {
140  die = true;
141  }
142 
143  // Feed the message to the MessageLogger and let it choose to suppress or not.
144 
145  // Root has declared a fatal error. Throw an EDMException unless the
146  // message corresponds to a pending signal. In that case, do not throw
147  // but let the OS deal with the signal in the usual way.
148  if (die && (el_location != std::string("@SUB=TUnixSystem::DispatchSignals"))) {
149  std::ostringstream sstr;
150  sstr << "Fatal Root Error: " << el_location << "\n" << el_message << '\n';
151  edm::Exception except(edm::errors::FatalRootError, sstr.str());
152  except.addAdditionalInfo(except.message());
153  except.clearMessage();
154  throw except;
155 
156  }
157 
158  // Typically, we get here only for informational messages,
159  // but we leave the other code in just in case we change
160  // the criteria for throwing.
161  if (el_severity == SeverityLevel::kFatal) {
162  edm::LogError("Root_Fatal") << el_location << el_message;
163  } else if (el_severity == SeverityLevel::kSysError) {
164  edm::LogError("Root_Severe") << el_location << el_message;
165  } else if (el_severity == SeverityLevel::kError) {
166  edm::LogError("Root_Error") << el_location << el_message;
167  } else if (el_severity == SeverityLevel::kWarning) {
168  edm::LogWarning("Root_Warning") << el_location << el_message ;
169  } else if (el_severity == SeverityLevel::kInfo) {
170  edm::LogInfo("Root_Information") << el_location << el_message ;
171  }
172  }
173 
174  void RootErrorHandler(int level, bool, char const* location, char const* message) {
175  RootErrorHandlerImpl(level, location, message);
176  }
177 
178  extern "C" {
179  void sig_dostack_then_abort(int sig,siginfo_t*,void*) {
180  if (gSystem) {
181  const char* signalname = "unknown";
182  switch (sig) {
183  case SIGBUS:
184  signalname = "bus error";
185  break;
186  case SIGSEGV:
187  signalname = "segmentation violation";
188  break;
189  case SIGILL:
190  signalname = "illegal instruction";
191  default:
192  break;
193  }
194  edm::LogError("FatalSystemSignal")<<"A fatal system signal has occurred: "<<signalname;
195  std::cerr<< "\n\nA fatal system signal has occurred: "<<signalname<<"\n"
196  <<"The following is the call stack containing the origin of the signal.\n"
197  <<"NOTE:The first few functions on the stack are artifacts of processing the signal and can be ignored\n\n";
198 
199  gSystem->StackTrace();
200  std::cerr<<"\nA fatal system signal has occurred: "<<signalname<<"\n";
201  }
202  ::abort();
203  }
204 
205  void sig_abort(int sig, siginfo_t*, void*) {
206  ::abort();
207  }
208  }
209 } // end of unnamed namespace
210 
211 namespace edm {
212  namespace service {
214  : RootHandlers(),
215  unloadSigHandler_(pset.getUntrackedParameter<bool> ("UnloadRootSigHandler")),
216  resetErrHandler_(pset.getUntrackedParameter<bool> ("ResetRootErrHandler")),
217  loadAllDictionaries_(pset.getUntrackedParameter<bool>("LoadAllDictionaries")),
218  autoLibraryLoader_(loadAllDictionaries_ or pset.getUntrackedParameter<bool> ("AutoLibraryLoader"))
219  {
220 
221  if(unloadSigHandler_) {
222  // Deactivate all the Root signal handlers and restore the system defaults
223  gSystem->ResetSignal(kSigChild);
224  gSystem->ResetSignal(kSigBus);
225  gSystem->ResetSignal(kSigSegmentationViolation);
226  gSystem->ResetSignal(kSigIllegalInstruction);
227  gSystem->ResetSignal(kSigSystem);
228  gSystem->ResetSignal(kSigPipe);
229  gSystem->ResetSignal(kSigAlarm);
230  gSystem->ResetSignal(kSigUrgent);
231  gSystem->ResetSignal(kSigFloatingException);
232  gSystem->ResetSignal(kSigWindowChanged);
233  } else if(pset.getUntrackedParameter<bool>("AbortOnSignal")){
234  //NOTE: ROOT can also be told to abort on these kinds of problems BUT
235  // it requires an TApplication to be instantiated which causes problems
236  gSystem->ResetSignal(kSigBus);
237  gSystem->ResetSignal(kSigSegmentationViolation);
238  gSystem->ResetSignal(kSigIllegalInstruction);
239  installCustomHandler(SIGBUS,sig_dostack_then_abort);
240  sigBusHandler_ = std::shared_ptr<const void>(nullptr,[](void*) {
241  installCustomHandler(SIGBUS,sig_abort);
242  });
243  installCustomHandler(SIGSEGV,sig_dostack_then_abort);
244  sigSegvHandler_ = std::shared_ptr<const void>(nullptr,[](void*) {
245  installCustomHandler(SIGSEGV,sig_abort);
246  });
247  installCustomHandler(SIGILL,sig_dostack_then_abort);
248  sigIllHandler_ = std::shared_ptr<const void>(nullptr,[](void*) {
249  installCustomHandler(SIGILL,sig_abort);
250  });
251  }
252 
253  if(resetErrHandler_) {
254 
255  // Replace the Root error handler with one that uses the MessageLogger
256  SetErrorHandler(RootErrorHandler);
257  }
258 
259  // Enable automatic Root library loading.
260  if(autoLibraryLoader_) {
261  gInterpreter->SetClassAutoloading(1);
262  }
263 
264  // Set ROOT parameters.
265  TTree::SetMaxTreeSize(kMaxLong64);
266  TH1::AddDirectory(kFALSE);
267  //G__SetCatchException(0);
268 
269  // Set custom streamers
271 
272  // Load the library containing dictionaries for std:: classes, if not already loaded.
273  if (!hasDictionary(typeid(std::vector<std::vector<unsigned int> >))) {
274  edmplugin::PluginCapabilities::get()->load(dictionaryPlugInPrefix() + "std::vector<std::vector<unsigned int> >");
275  }
276 
277  int debugLevel = pset.getUntrackedParameter<int>("DebugLevel");
278  if(debugLevel >0) {
279  gDebug = debugLevel;
280  }
281  }
282 
284  // close all open ROOT files
285  TIter iter(gROOT->GetListOfFiles());
286  TObject *obj = nullptr;
287  while(nullptr != (obj = iter.Next())) {
288  TFile* f = dynamic_cast<TFile*>(obj);
289  if(f) {
290  // We get a new iterator each time,
291  // because closing a file can invalidate the iterator
292  f->Close();
293  iter = TIter(gROOT->GetListOfFiles());
294  }
295  }
296  }
297 
299  //Tell Root we want to be multi-threaded
300  TThread::Initialize();
301  //When threading, also have to keep ROOT from logging all TObjects into a list
302  TObject::SetObjectStat(false);
303 
304  //Have to avoid having Streamers modify themselves after they have been used
305  TVirtualStreamerInfo::Optimize(false);
306  }
307 
309  static thread_local TThread guard;
310  }
311 
314  desc.setComment("Centralized interface to ROOT.");
315  desc.addUntracked<bool>("UnloadRootSigHandler", false)
316  ->setComment("If True, signals are handled by this service, rather than by ROOT.");
317  desc.addUntracked<bool>("ResetRootErrHandler", true)
318  ->setComment("If True, ROOT messages (e.g. errors, warnings) are handled by this service, rather than by ROOT.");
319  desc.addUntracked<bool>("AutoLibraryLoader", true)
320  ->setComment("If True, enables automatic loading of data dictionaries.");
321  desc.addUntracked<bool>("LoadAllDictionaries",false)
322  ->setComment("If True, loads all ROOT dictionaries.");
323  desc.addUntracked<bool>("AbortOnSignal",true)
324  ->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.");
325  desc.addUntracked<int>("DebugLevel",0)
326  ->setComment("Sets ROOT's gDebug value.");
327  descriptions.add("InitRootHandlers", desc);
328  }
329 
330  void
332  s_ignoreWarnings =false;
333  }
334 
335  void
337  s_ignoreWarnings = true;
338  }
339 
340  } // end of namespace service
341 } // 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)