How to get unix signals into Qt? (Embedded Linux)



  • Hi

    Is there a way to get unix signals into the Qt world in a good way?

    I tried to follow this example but it's not working for me.

    bq.

    Firstly I the code is hard to get to compile to start with,
    and after a while when I got it compiling the QSocketNotifier don't seem to work.

    Can someone push me in the right direction on this topic?

    Thanks
    Johan



  • Hi there!

    I read your question and got interested, since I've never needed to handle unix signals in a Qt app.

    [quote author="jsiei97" date="1286809378"]
    I tried to follow this example but it's not working for me.

    Firstly I the code is hard to get to compile to start with,
    [/quote]

    I followed the same instructions and example. Indeed, to build the example you need to know some things not mentioned in the doc + deal with static class members (not so obvious for C++ begginners, IMHO.).

    [quote author="jsiei97" date="1286809378"]
    and after a while when I got it compiling the QSocketNotifier don't seem to work.
    Can someone push me in the right direction on this topic?
    [/quote]

    Example built, I tested it successfully with both SIGTERM and SIGHUP. How did you test it?

    Maybe you did the same, but just to be sure, here is my test steps:

    run the example in a terminal, then in another terminal:

    for SIGHUP: kill -1 <example PID> or

    for SIGTERM: kill -15 <example PID>



  • I used the kill command, and got feedback from a print I added in the "unix signal handler function". But I never got any reaction in the Qt signal slot function that was supposed to run with some help from QSockerNotifier.

    And I also had to add some stuff, but I have no idea if I added the correct stuff...



  • Ok, here is the example code + things added to build:

    • mydaemon.h:
      @
      #include <QSocketNotifier>

    class MyDaemon : public QObject
    {
    Q_OBJECT

    public:
    MyDaemon(QObject *parent = 0, const char *name = 0);
    ~MyDaemon();

    // Unix signal handlers.
    static void hupSignalHandler(int unused);
    static void termSignalHandler(int unused);

    public slots:
    // Qt signal handlers.
    void handleSigHup();
    void handleSigTerm();

    private:
    static int sighupFd[2];
    static int sigtermFd[2];

    QSocketNotifier *snHup;
    QSocketNotifier *snTerm;
    };
    @

    • mydaemon.cpp:
      @
      #include "mydaemon.h"

    #include <QDebug>
    #include <csignal>
    #include <sys/socket.h>

    //needed to not get an undefined reference to static members
    int MyDaemon::sighupFd[2];
    int MyDaemon::sigtermFd[2];

    MyDaemon::MyDaemon(QObject *parent, const char *name)
    : QObject(parent)
    {
    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sighupFd))
    qFatal("Couldn't create HUP socketpair");

    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigtermFd))
    qFatal("Couldn't create TERM socketpair");
    snHup = new QSocketNotifier(sighupFd[1], QSocketNotifier::Read, this);
    connect(snHup, SIGNAL(activated(int)), this, SLOT(handleSigHup()));
    snTerm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this);
    connect(snTerm, SIGNAL(activated(int)), this, SLOT(handleSigTerm()));
    }

    MyDaemon::~MyDaemon() {}

    static int setup_unix_signal_handlers()
    {
    struct sigaction hup, term;

    hup.sa_handler = MyDaemon::hupSignalHandler;
    sigemptyset(&hup.sa_mask);
    hup.sa_flags = 0;
    hup.sa_flags |= SA_RESTART;

    if (sigaction(SIGHUP, &hup, 0) > 0)
    return 1;

    term.sa_handler = MyDaemon::termSignalHandler;
    sigemptyset(&term.sa_mask);
    term.sa_flags |= SA_RESTART;

    if (sigaction(SIGTERM, &term, 0) > 0)
    return 2;

    return 0;
    }

    void MyDaemon::hupSignalHandler(int)
    {
    char a = 1;
    ::write(sighupFd[0], &a, sizeof(a));
    }

    void MyDaemon::termSignalHandler(int)
    {
    char a = 1;
    ::write(sigtermFd[0], &a, sizeof(a));
    }

    void MyDaemon::handleSigTerm()
    {
    snTerm->setEnabled(false);
    char tmp;
    ::read(sigtermFd[1], &tmp, sizeof(tmp));

    // do Qt stuff

    snTerm->setEnabled(true);
    }

    void MyDaemon::handleSigHup()
    {
    snHup->setEnabled(false);
    char tmp;
    ::read(sighupFd[1], &tmp, sizeof(tmp));

    // do Qt stuff

    snHup->setEnabled(true);
    }
    @

    • main.cpp
      @
      #include <QCoreApplication>

    #include "mydaemon.h"

    int main(int argc, char *argv[])
    {
    QCoreApplication app(argc, argv);
    MyDaemon d;

    return app.exec&#40;&#41;;
    

    }
    @

    @jsiei97, I'll add stuff to the Qt slots and check.



  • Hi

    Your example is close, but who is calling setup_unix_signal_handlers()?
    I can't get any response with kill with your code.

    However I updated my with some parts that you added and got the code attached.

    And this code gave me this output

    @
    Qt and unix signals
    SIGHUP; kill -1 14795
    SIGTERM; kill -15 14795
    signal hup
    1signal hup
    1signal hup
    1signal hup
    1
    @

    Notice that strange '1' that seem to come from "snHup",
    but I never see the "real" print in MyDaemon::handleSigHup()...

    So I am a little confused here..

    main.cpp
    @
    #include <QCoreApplication>
    #include <QDebug>

    #include <signal.h>
    #include <unistd.h>

    #include "MyDaemon.h"

    static int setup_unix_signal_handlers()
    {
    int mypid = getpid();

    struct sigaction hup, term;
    
    hup.sa_handler = MyDaemon::hupSignalHandler;
    sigemptyset(&hup.sa_mask);
    hup.sa_flags = 0;
    hup.sa_flags |= SA_RESTART;
    
    if (sigaction(SIGHUP, &hup, 0) > 0)
        return 1;
    
    qDebug("SIGHUP; kill -%d %d", SIGHUP, mypid);
    
    term.sa_handler = MyDaemon::termSignalHandler;
    sigemptyset(&term.sa_mask);
    term.sa_flags |= SA_RESTART;
    
    if (sigaction(SIGTERM, &term, 0) > 0)
        return 2;
    
    qDebug("SIGTERM; kill -%d %d", SIGTERM, mypid);
    
    return 0;
    

    }

    /**

    • http://doc.trolltech.com/4.6/unix-signals.html
      */
      int main(int argc, char *argv[])
      {
      QCoreApplication app(argc, argv);
      qDebug() << "Qt and unix signals";

      setup_unix_signal_handlers();

      MyDaemon daemon();

      //while(1)
      //{
      // sleep(1);
      //}
      return app.exec();
      }
      @

    MyDaemon.h
    @
    #include <QObject>
    #include <QSocketNotifier>

    class MyDaemon : public QObject
    {
    Q_OBJECT

    public:
        MyDaemon(QObject *parent = 0, const char *name = 0);
        ~MyDaemon();
    
        // Unix signal handlers.
        static void hupSignalHandler(int unused);
        static void termSignalHandler(int unused);
    
    public slots:
        // Qt signal handlers.
        void handleSigHup();
        void handleSigTerm();
    
    private:
        static int sighupFd[2];
        static int sigtermFd[2];
    
        QSocketNotifier *snHup;
        QSocketNotifier *snTerm;
    

    };
    @

    MyDaemon.cpp
    @
    #include "MyDaemon.h"

    #include <QDebug>
    #include <QObject>
    #include <QSocketNotifier>
    #include <csignal>
    #include <sys/socket.h>

    //needed to not get an undefined reference to static members
    int MyDaemon::sighupFd[2];
    int MyDaemon::sigtermFd[2];

    MyDaemon::MyDaemon(QObject *parent, const char *name)
    : QObject(parent)
    {
    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sighupFd))
    qFatal("Couldn't create HUP socketpair");

    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigtermFd))
        qFatal("Couldn't create TERM socketpair");
    
    snHup = new QSocketNotifier(sighupFd[1], QSocketNotifier::Read, this);
    connect(snHup, SIGNAL(activated(int)), this, SLOT(handleSigHup()));
    snTerm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this);
    connect(snTerm, SIGNAL(activated(int)), this, SLOT(handleSigTerm()));
    

    }

    MyDaemon::~MyDaemon() {}

    void MyDaemon::hupSignalHandler(int)
    {
    qDebug() << "signal hup";
    char a = '1';
    ::write(sighupFd[0], &a, sizeof(a));

    }

    void MyDaemon::termSignalHandler(int)
    {
    qDebug() << "signal term";
    char a = '2';
    ::write(sigtermFd[0], &a, sizeof(a));
    }

    void MyDaemon::handleSigTerm()
    {
    snTerm->setEnabled(false);
    char tmp;
    ::read(sigtermFd[1], &tmp, sizeof(tmp));

    // do Qt stuff
    qDebug() << "MyDaemon::handleSigTerm";
    
    snTerm->setEnabled(true);
    

    }

    void MyDaemon::handleSigHup()
    {
    snHup->setEnabled(false);
    char tmp;
    ::read(sighupFd[1], &tmp, sizeof(tmp));

    // do Qt stuff
    qDebug() << "MyDaemon::handleSigHup";
    
    snHup->setEnabled(true);
    

    }
    @



  • I noticed that I was calling the wrong constructor...?

    Adding some NULL as args was quite useful :)

    This is the working main function.
    @
    int main(int argc, char *argv[])
    {
    QCoreApplication app(argc, argv);
    qDebug() << "Qt and unix signals";

    setup_unix_signal_handlers();
    
    MyDaemon daemon(NULL,NULL);
    
    return app.exec();
    

    }
    @

    Thanks for the help.

    BR
    Johan



  • gosh! I posted the wrong main.cpp - this was the first successfully built, not the tested one.
    Nice to see you solved it, I'll check later (/me answering from my mobile =)



  • Ok, now I can read the code properly in a bigger screen.

    The correct main.cpp file looks like yours, the only difference is that I made setup_unix_signal_handlers() a static method of MyDaemon, then I call MyDaemon::setup_unix_signal_handlers() . But it is just a implementation detail (Yes, the mydaemon.h I posted here does not contains the correct declaration of such method... a problem of editing one file, copy-and-pasting another one).

    One thing I did not understand is: why did you add NULL args when instantiating MyDaemon in your main.cpp?
    AFAIK "in C++ NULL == 0":http://www2.research.att.com/~bs/bs_faq2.html#null, so as the default values for the MyDameon constructor are 0, it should not make any difference.



  • why did you add NULL args when instantiating MyDaemon

    That one is interesting, without them my program did not run the correct constructor.
    So in my case the unix signal handler was not initialized, and the notifier and socket/slot was not setup correctly.

    So I added (NULL, NULL) to match MyDaemon(QObject *parent, const char *name),
    but I agree that it is strange that I needed to add this step.

    Could it be that the program actually used some other constructor? Maybe one inherited from QObject? And that was why the compiler did not complain?

    /Johan



  • [quote author="jsiei97" date="1287126448"]
    Could it be that the program actually used some other constructor? Maybe one inherited from QObject? And that was why the compiler did not complain?
    [/quote]

    Hm... I don't know, need to look carefully, I'm curious now.



  • Thanks for your post. I ran across it and am glad someone else had issues. In my case, the following post was very helpful in debugging. Thanks to this thread, I was able to compile and get my code working. :)

    @
    //needed to not get an undefined reference to static members
    int MyDaemon::sighupFd[2];
    int MyDaemon::sigtermFd[2];
    @



  • I found it cannot inherit from QObject, the complier will report an error:undefined reference to vtable for XX.
    Have you guys found this?



  • It's because the compiler does not know that one of your classes is now QObject-inherited. Either rebuild the whole project from scratch, or modify your *.pro file (e.g. by typing a letter and deleting it) and then recompile.

    [quote author="lanmanck" date="1368066317"]I found it cannot inherit from QObject, the complier will report an error:undefined reference to vtable for XX.
    Have you guys found this?[/quote]


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.