Skip to content

Commit 697a0b0

Browse files
committed
[core] Ensure registration of atexit function is done only once
Before this commit, the following triggered two calls to TROOT::EndOfProcessCleanups: python -c "import ROOT; ROOT.TH1F" This happened because the TApplication constructor registered a function that calls EndOfProcessCleanups with the C `atexit` and PyROOT registered another similar function with the Python atexit module in `__init__.py`. The Python atexit happened before the C atexit. This commit introduces a static function in TApplication that registers the call to EndOfProcessCleanups with the C `atexit` and this is guaranteed to be run only once through the use of std::call_once. This new function can be called both from PyROOT and the TApplication constructor, to make sure it will be registered by either of them. Furthermore, calling this from PyROOT means that now EndOfProcessCleanups is always called at the very end of the program, seemingly a more sensible choice.
1 parent f8b8277 commit 697a0b0

File tree

3 files changed

+16
-7
lines changed

3 files changed

+16
-7
lines changed

bindings/pyroot/pythonizations/python/ROOT/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ def cleanup():
7979
# Hard teardown: run part of the gROOT shutdown sequence.
8080
# Running it here ensures that it is done before any ROOT libraries
8181
# are off-loaded, with unspecified order of static object destruction.
82-
backend.gROOT.EndOfProcessCleanups()
82+
from ROOT import TApplication
83+
TApplication.RegisterEndOfProcessCleanups()
8384

8485
atexit.register(cleanup)

core/base/inc/TApplication.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ class TApplication : public TObject, public TQObject {
158158
static TList *GetApplications();
159159
static void CreateApplication();
160160
static void NeedGraphicsLibs();
161+
static void RegisterEndOfProcessCleanups();
161162

162163
ClassDefOverride(TApplication,0) //GUI application singleton
163164
};

core/base/src/TApplication.cxx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,13 @@ TApplication (see TRint).
4949
#include <cstdlib>
5050
#include <iostream>
5151
#include <fstream>
52+
#include <mutex>
5253

5354
TApplication *gApplication = nullptr;
5455
Bool_t TApplication::fgGraphNeeded = kFALSE;
5556
Bool_t TApplication::fgGraphInit = kFALSE;
5657
TList *TApplication::fgApplications = nullptr; // List of available applications
58+
std::once_flag gRegisterEndOfProcessCleanupsFlag;
5759

5860
////////////////////////////////////////////////////////////////////////////////
5961

@@ -91,6 +93,15 @@ static void CallEndOfProcessCleanups()
9193
}
9294
}
9395

96+
////////////////////////////////////////////////////////////////////////////////
97+
/// Register an atexit function that calls TROOT::EndOfProcessCleanups.
98+
///
99+
/// The registration is done only once in the program by using an std::once_flag.
100+
void TApplication::RegisterEndOfProcessCleanups()
101+
{
102+
std::call_once(gRegisterEndOfProcessCleanupsFlag, []{ std::atexit(CallEndOfProcessCleanups); });
103+
}
104+
94105
////////////////////////////////////////////////////////////////////////////////
95106
/// Default ctor. Can be used by classes deriving from TApplication.
96107

@@ -156,12 +167,8 @@ TApplication::TApplication(const char *appClassName, Int_t *argc, char **argv,
156167
if (!gSystem)
157168
::Fatal("TApplication::TApplication", "gSystem not initialized");
158169

159-
static Bool_t hasRegisterAtExit(kFALSE);
160-
if (!hasRegisterAtExit) {
161-
// If we are the first TApplication register the atexit)
162-
atexit(CallEndOfProcessCleanups);
163-
hasRegisterAtExit = kTRUE;
164-
}
170+
TApplication::RegisterEndOfProcessCleanups();
171+
165172
gROOT->SetName(appClassName);
166173

167174
// copy command line arguments, can be later accessed via Argc() and Argv()

0 commit comments

Comments
 (0)