Signalhandler not working when method called via popup menu

Hello,

In my GUI application I have a class with some methods declared as appearing in the context menu (using the // *MENU* comment after the function definition).

I am finding that when these methods are called via the menu, I cannot interrupt the method with the usual Ctrl+C. If I call the method from the interpreter prompt I can interrupt. I’ve tried defining my own custom TSignalHandler but that hasn’t worked. It appears as though the signals aren’t processed until after the method has finished.

Is there a way I can do signal handling (specifically SIGINT) on a method called by the context menu?

Thanks
Will

can you provide an example we can try?

Ok here’s one that reproduces effect for me:


#include <TH1D.h>
#include <TSystem.h>
#include <thread>
#include <iostream>

class MyClass : public TH1D {
  public:
    using TH1D::TH1D;
    void MyMethod(); // *MENU*
    ClassDefOverride(MyClass,0)
};
void interruptHandler(int signum) {
    std::cout << "Received " << signum << std::endl;
};
void MyClass::MyMethod() {
    auto oldHandlerr = signal(SIGINT, interruptHandler);
    std::cout << "starting to sleep" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(5));
    std::cout << "done" << std::endl;
    signal(SIGINT, oldHandlerr);
}

load this as a compiled macro, then on the ROOT prompt do:

MyClass d("d","d",10,0,10);d.MyMethod();

Hit Ctrl+C a few times, you see the signal handler captures fine.
Now do d.Draw() and right click on the histogram and select MyMethod … then try Ctrl+C … nothing!

OK, I see, but I think there is not much we can do here. I’ll investigate nevertheless. BTW, which platform are you working on?

x86 macos, ROOT 6.28.04

Thanks for looking, I hope it turns out there is a way to interrupt a method invoked via GUI. I want a user to have a way to exit from a long calculation that one of my methods provides, which they can do if they call the method from the prompt, but not if they do it from the GUI.

The problem it that in the gui the events are not processed via the console…

Here is another approach:

#include <TROOT.h>
#include <TH1D.h>
#include <TSystem.h>
#include <TThread.h>
#include <iostream>

class MyClass : public TH1D {
  public:
    using TH1D::TH1D;
    TThread *myThread;
    void MyMethod(); // *MENU*
    ClassDefOverride(MyClass,0)
};

void *myFunction(void *p)
{
   std::cout << "Running";
   while(1) {
      // sleep 100ms
      gSystem->Sleep(100);
      std::cout << '.';
      if (gROOT->IsInterrupted())
          break;
   }
   return 0;
}

void MyClass::MyMethod() {
    std::cout << "starting my thread" << std::endl;
    myThread = new TThread("myThread", myFunction, this);
    myThread->Run();
    myThread->Join();
    std::cout << "done" << std::endl;
}

And interrupt it via the Canvas OptionInterrupt menu entry. ut that only works if you have a loop and can check for gROOT->IsInterrupted()
(and sorry for using the obsolete TThread class, but I’m sure you get the idea)

Or even better, something like this:

#include <TROOT.h>
#include <TH1D.h>
#include <TSystem.h>
#include <TThread.h>
#include <signal.h>
#include <iostream>

class MyClass : public TH1D {
  public:
    using TH1D::TH1D;
    TThread *myThread;
    void MyMethod(); // *MENU*
    ClassDefOverride(MyClass,0)
};

void *myFunction(void *p)
{
   std::cout << "Running";
   while(1) {
      // sleep 100ms
      gSystem->Sleep(100);
      std::cout << '.';
      if (gROOT->IsInterrupted()) {
          std::cout << std::endl;
          raise(SIGINT);
          break;
      }
   }
   return 0;
}

void interruptHandler(int signum) {
    std::cout << "Received " << signum << std::endl;
};

void MyClass::MyMethod() {
    auto oldHandlerr = signal(SIGINT, interruptHandler);
    std::cout << "starting my thread" << std::endl;
    myThread = new TThread("myThread", myFunction, this);
    myThread->Run();
    myThread->Join();
    std::cout << "done" << std::endl;
    signal(SIGINT, oldHandlerr);
}

So you can still use the SIGINT signal…

root [0] .L myclass.h+
root [1] MyClass d("d","d",10,0,10);
root [2] d.Draw();
Info in <TCanvas::MakeDefCanvas>:  created default TCanvas with name c1
root [3] starting my thread
Running....................................................................
Received 2
done

Ok thanks for these suggestions. I’ve been trying them for the past 30 mins and can’t yet make things work properly but I’ll keep trying. I haven’t checked yet if one of my issues is that I have methods that accept arguments so I get argument dialog box and that stays visible after hitting ok, and I can’t go in and interrupt gROOT via the GUI.

I’ll keep trying though …

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.