ATLAS Offline Software
WithRootErrorHandler.cxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration.
3  */
13 #include <vector>
14 #include <cstdlib>
15 #include <mutex>
16 #include <atomic>
17 
18 
19 namespace {
20 
21 
24 thread_local std::vector<Handler_t> rootErrorHandlers;
25 
26 
28 std::atomic<ErrorHandlerFunc_t> origHandler;
29 
30 
34 void errorHandler (int level,
35  Bool_t abort,
36  const char* location,
37  const char* msg)
38 {
39  // Execute all the handlers in our thread-local list from newest to oldest.
40  // Stop if one returns false.
41  for (int i = rootErrorHandlers.size()-1; i >= 0; --i) {
42  if (!rootErrorHandlers[i] (level, abort, location, msg)) return;
43  }
44  // They all returned true. Call the previous handler.
45  origHandler.load() (level, abort, location, msg);
46 }
47 
48 
49 } // anonymous namespace
50 
51 
52 namespace RootUtils {
53 
54 
66  : m_size (rootErrorHandlers.size()+1)
67 {
68  // Install our handler the first time we're called.
69  // We used to do that when the library was loaded, via a global static,
70  // but then we ran to issues where the behavior could depend on library
71  // loading order, since other libraries (such as Gaudi) also try to install
72  // their own handler.
73  //
74  // By the time we're called, there may be multiple threads running,
75  // so it is in principle not safe to call SetErrorHandler.
76  // However, there shouldn't be anything else in Athena calling it,
77  // so in practice it should be ok. As an extra check, we abort if the
78  // handler we get back isn't what we set, indicating a potential race.
79  //
80  // See ATLASRECTS-7967.
81  static std::once_flag flag;
82  std::call_once (flag, []() {
83  origHandler = ::SetErrorHandler (errorHandler);
84  if (::GetErrorHandler() != errorHandler) {
85  std::abort();
86  }
87  });
88 
89  rootErrorHandlers.push_back (errhand);
90 }
91 
92 
99 {
100  if (m_size != rootErrorHandlers.size()) std::abort();
101  rootErrorHandlers.pop_back();
102 }
103 
104 
105 } // namespace RootUtils
RootUtils
Definition: ILogger.h:20
RootUtils::WithRootErrorHandler::Handler_t
std::function< bool(int, Bool_t, const char *, const char *)> Handler_t
Type of handler to register.
Definition: WithRootErrorHandler.h:63
python.iconfTool.models.loaders.level
level
Definition: loaders.py:20
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
RootUtils::WithRootErrorHandler::WithRootErrorHandler
WithRootErrorHandler(Handler_t errhand)
Temporarily install a thread-local root error handler.
Definition: WithRootErrorHandler.cxx:65
lumiFormat.i
int i
Definition: lumiFormat.py:92
python.sizes.location
string location
Definition: sizes.py:11
master.flag
bool flag
Definition: master.py:29
RootUtils::WithRootErrorHandler::~WithRootErrorHandler
~WithRootErrorHandler()
Destructor.
Definition: WithRootErrorHandler.cxx:98
WithRootErrorHandler.h
Run a MT piece of code with an alternate root error handler.
RootUtils::WithRootErrorHandler::m_size
size_t m_size
For error checking.
Definition: WithRootErrorHandler.h:101
python.AutoConfigFlags.msg
msg
Definition: AutoConfigFlags.py:7