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