SoFunction
Updated on 2025-04-06

Detailed explanation of the example of C/C++ implementation to capture all signals

1. Principle

Linux signals may occur without you realizing them.

For example, if the socket network is disconnected, by default, SIGPIPE is sent to the process in send/recv to kill the process. Forget it and it is very troublesome to handle this. The program is normal most of the time and occasionally terminates strangely. It may take a lot of effort to find the reason.

Linux signals do not contain any data. What if you know that a connection is disconnected? I don't know which connection is disconnected (in fact, we will process it based on the return value of send/recv).

So in order to save effort, we can capture all signals at the beginning of the program and then process them in a targeted manner according to the actual runtime situation (most cases do not require any processing at all).

More knowledge about signals is in the "Signal Description" function later.

2. Basics

The easiest way to process signals is to call the signal function, which sets the signal processing method and returns the previous signal processing method (so that you can call the original processing method before or after executing your own processing to form a call chain).

       #include <>
 
       typedef void (*sighandler_t)(int);
 
       sighandler_t signal(int signum, sighandler_t handler);

There are several forms of signal, but this is the simplest.

3. Code

Code to capture all signals

    int __all_sig_catch(int argc, char ** argv, int fun(int, char **))
    {
        signal(SIGABRT, sig_default);
        signal(SIGALRM, sig_default);
        signal(SIGBUS, sig_default);
        signal(SIGCHLD, sig_default);
        signal(SIGCONT, sig_default);
        signal(SIGFPE, sig_default);
        signal(SIGHUP, sig_default);
        signal(SIGILL, sig_default);
        //signal(SIGINT, sig_default);//ctrl-c
        signal(SIGIO, sig_default);
        signal(SIGIOT, sig_default);
        signal(SIGKILL, sig_default);
        signal(SIGPIPE, sig_default);
        signal(SIGPOLL, sig_default);
        signal(SIGPROF, sig_default);
        signal(SIGPWR, sig_default);
        signal(SIGQUIT, sig_default);
        signal(SIGSEGV, sig_default);
        signal(SIGSTOP, sig_default);
        signal(SIGSYS, sig_default);
        signal(SIGTERM, sig_default);
        signal(SIGTRAP, sig_default);
        signal(SIGTSTP, sig_default);
        signal(SIGTTIN, sig_default);
        signal(SIGTTOU, sig_default);
        signal(SIGURG, sig_default);
        signal(SIGUSR1, sig_default);
        signal(SIGUSR2, sig_default);
        signal(SIGVTALRM, sig_default);
        signal(SIGWINCH, sig_default);
        signal(SIGXCPU, sig_default);
        signal(SIGXFSZ, sig_default);
 
        int ret;
        try
        {
            ret = fun(argc, argv);
        }
        catch (...)
        {
            thelog &lt;&lt; "Unhandled exception occurs" &lt;&lt; ende;
            return __LINE__;
        }
        return ret;
    }

The method of calling this function is to put a shell on the main function. Of course, you can also remove all the parameters and only retain the part of the signal processing function.

SIGINT is not captured, this is the signal generated by ctrl-c, and I do need to end the program like this.

Finally, I caught some unhandled exceptions, which is also the part that is often overlooked. If you need to generate a core file, you can call abort().

Note that SIGKILL and SIGSTOP are not captured (although there is one in the above code).

Call code

int _main(int argc, char ** argv)
{
    ......
}
int main(int argc, char ** argv)
{
    return __all_sig_catch(argc, argv, _main);
}

Signal processing function

sig_default is a set signal processing function and must meet the requirements of the signal function:

    extern "C" void sig_default(int sig)
    {
        signal(sig, sig_default);
        cout << "p " << sigstr(sig) << endl;
    }

Note that it must be extern "C". Signal is called again in the code to set the signal processing function. I am not sure about the reason for doing this now, but at least there should be no problem with doing this.

Strictly speaking, the previous processing function should be called, but this will be very complicated. Because we set it at the beginning of the main function, all signals should not have been set yet.

Signal description

sigstr is a function that outputs the signal name:

    //Signal description    char const * sigstr(long sig)
    {
        switch(sig)
        {
        case SIGABRT    :    return "The SIGABRT process calls the abort function, and the process exits abnormally";
        case SIGALRM    :    return "SIGALRM timeout set by alarm function or interval timeout set by settimer function";
        case SIGBUS     :    return "SIGBUS A specific hardware exception, usually caused by memory access";
        case SIGCHLD    :    return "SIGCHLD child process Terminate or Stop";
        case SIGCONT    :    return "SIGCONT resumes running from stop";
#ifndef _LINUXOS
        case SIGEMT     :    return "SIGEMT and implementation-related hardware exceptions";
#endif
        case SIGFPE     :    return "SIGFPE mathematical exceptions, such as dividing by 0, floating point overflow, etc.";
        case SIGHUP     :    return "SIGHUP Terminal Disconnected";
        case SIGILL     :    return "SIGILL Illegal Directive Exception";
            //case SIGINFO : return "SIGINFO BSD signal. Generated by Status Key, usually CTRL+T. Sent to all Foreground Group processes ";        case SIGINT     :    return "SIGINT is generated by Interrupt Key, usually CTRL+C or DELETE";
        case SIGIO      :    return "SIGIO asynchronous IO event";
            //case SIGIOT : return "SIGIOT implementation-related hardware exceptions, generally corresponding to SIGABRT";        case SIGKILL    :    return "SIGKILL Forced Abort";
        case SIGPIPE    :    return "SIGPIPE is sent when writing Pipe after reader abort";
            //case SIGPOLL : return "SIGPOLL Send when an event is sent to Pollable Device";        case SIGPROF    :    return "Created by Profiling Interval Timer specified by SIGPROF Setitimer";
        case SIGPWR     :    return "SIGPWR is related to the system. It is related to the UPS.";
        case SIGQUIT    :    return "SIGQUIT Enter Quit Key (CTRL+\\)";
        case SIGSEGV    :    return "SIGSEGV Illegal Memory Access";
        case SIGSTOP    :    return "SIGSTOP aborts the process";
        case SIGSYS     :    return "SIGSYS Illegal System Call";
        case SIGTERM    :    return "SIGTERM request to abort the process, the kill command is sent by default";
        case SIGTRAP    :    return "SIGTRAP implementation-related hardware exceptions. Generally, debugging exceptions";
        case SIGTSTP    :    return "SIGTSTP Suspend Key, usually Ctrl+Z";
        case SIGTTIN    :    return "SIGTTIN is sent when the Background Group process tries to read Terminal";
        case SIGTTOU    :    return "SIGTTOU is sent when the Background Group process tries to write Terminal";
        case SIGURG     :    return "SIGURG may be sent when out-of-band data is received";
        case SIGUSR1    :    return "SIGUSR1 User-defined signal 1";
        case SIGUSR2    :    return "SIGUSR2 User-defined signal 2";
        case SIGVTALRM  :    return "When the Virtual Interval Timer timeout set by SIGVTALRM setitimer function";
        case SIGWINCH   :    return "SIGWINCH When the size of the Terminal window changes, send it to all processes in the Foreground Group";
        case SIGXCPU    :    return "SIGXCPU When the CPU time limit is timed out";
        case SIGXFSZ    :    return "SIGXFSZ process exceeds file size limit";
        default:             return "Unknown Signal";
        }
    }

Some of the blocking is due to compatibility issues (this code was previously run on small computers of IBM, SUN, and HP, and later changed to run on Linux), you can add it as needed.

This is the end of this article about the detailed explanation of C/C++ implementation of all signals. For more related content on C++ capturing all signals, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!