PyROOT and Interrupts / OS Signals

Dear PyRooters,

I’m calling a few long-running things in C++, which I would like to be able to abort by pressing CTRL-C. The problem is that I can’t see any way of setting up a signal handler with ROOT. I tried something like the following:

sh = ROOT.TSignalHandler( ROOT.kSigInterrupt, False ) sh.Add() ROOT.gSystem.AddSignalHandler(sh) sh.Connect( "Notified()", "TApplication", ROOT.TROOT, "SetInterrupt()" )

with a check for gROOT->IsInterrupted() within my long-running loops (also, TTree::Draw I believe checks such things).

I’ve not had much luck, I guess because I need to TApplication::SetSignalHandler(), which is protected?

Any thoughts appreciated…

Hi,

hitting CTRL-C during the run of C++ won’t yield a decent location to continue, so what I usually do is CTRL-\ (SIGQUIT) which python leaves alone and results in an abort. The calls “sh.Add()” and “ROOT.gSystem.AddSignalHandler(sh)” are equivalent, so only one is needed. The use of TROOT::SetInterrupt() would not work since python starts up a separate thread that calls TSystem::ProcessEvents() which resets gROOT’s interrupt on each call. I’m not too familiar with Connect, but I think that the second argument should be the class of the third argument, which should be an object (so “TROOT” and ROOT.gROOT, respectively in your example).

For a proof of concept, please run the following code:[code]import ROOT

sh = ROOT.TSignalHandler( ROOT.kSigInterrupt, False )
sh.Add()
print ROOT.gROOT.IsBatch()
sh.Connect( “Notified()”, “TROOT”, ROOT.gROOT, “SetBatch()” )[/code]from a file onto an interactive python session in non-batch mode. A printout of ‘0’ should appear. Then continue by hitting CTRL-C: nothing should happen, whereas normal python behavior is to show a KeyboardInterrupt. Then do “print ROOT.gROOT.IsBatch()” which should now give you the printout ‘1’.

HTH,
Wim

Well, like TTree::Draw(), in my loop I have a gROOT->IsInterrupted() which should tell me if ctrl-c was pressed and if I should break out of the loop?

The TApplication was from where I had tried a few different signals with no luck.

Regards,

  • Pete

Pete,

the gROOT fInterrupt will be set just fine if “SetInterrupt()” is used instead of the proof-of-concept “SetBatch()” in the example. Just that it will be erased in many different places in the ROOT sources (just do a grep on SetInterrupt), most notably in TSystem::ProcessEvents. You could use it anyway and hit CTRL-C a couple of times until you get lucky. In fact, in an interactive program, where there is a single dispatch to a long-winding C++ function, everything works as expected b/c the GIL is not released.

For example, file peter.C:[code]#include “TROOT.h”
#include

void runforever() {
for ( int i = 0; ; ++i ) {
std::cout << "running: " << i << std::endl;
if ( gROOT->IsInterrupted() ) {
std::cout << “stopped!” << std::endl;
break;
}
}
}[/code]
and file peter.py:[code]import ROOT

ROOT.gROOT.LoadMacro( “peter.C+” )
sh = ROOT.TSignalHandler( ROOT.kSigInterrupt, False )
sh.Add()
sh.Connect( “Notified()”, “TROOT”, ROOT.gROOT, “SetInterrupt()” )
ROOT.runforever()[/code]
followed by running: $ python -i peter.py
behaves as expected when CTRL-C is hit.

HTH,
Wim

Ah, yes. This looks like what I was after, thanks :slight_smile: