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