Tag Archive : signal

/ signal

POSIX/ANSI Signal and Signal Handling in C++

December 9, 2015 | Article | No Comments

In Linux and UNIX world, signals is defined as notifications to a process that an event has occurred. In details, a signal is a software interrupt which delivered by process or kernel. Signal occur asynchronously, which means the process doesn’t know ahead of time when a signal will occur.

Signal can be sent in following scenario:

  1. by one process to another process (or to itself)
  2. by kernel to a process

When an application receive signal, it postpone the current activity and work other thing based on interrupt (signal) it receive. Any application has default behavior for some signal, i.e. a process terminated when it receives an interrupt SIGNINT signal by pressing keystroke Ctrl-C. A programmer can modify the behavior by his own code when application receive specific signal, which will be discussed in this article.

This article is tested using following tools & environment:

  1. Slackware64 14.0 (Linux)
  2. gcc 4.7.1

Note that not all signals can be handled.

The Theory

To handle a signal, one should define a callback function to manage the signal. This callback will be registered so it will change the default behavior of signal handler.

There are several types available which can be read on appendix A section.

Sending a signal from terminal can be down using a “kill” command. Despite of the name, kill is not only for killing an application (thought it is when you don’t specify any signal number). To send a signal, the following is the general syntax:

kill -s <signal-number> <pid>

With <signal-number> is the signal number as specified on table appendix A and pid is the process id we want to send to.

Handling a Signal using Signal Function

The easiest way to handling a signal is using signal function to register signal callback.

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

// Define the function to be called when Ctrl-C (SIGINT) signal is sent to process
void callback_sigint(int signum) {
    // prompt that we got SIGINT
    printf("We got signal %d\n", signum);

    // Terminate program
    exit(signum);
}

int main() {
    // Register signal and signal handler
    signal(SIGINT, callback_sigint);

    while (true) {
         printf("Program is processing stuff here.\n");
         sleep(1);
    }
    return 0;
}

Compile and followed by run:

gcc SignalExample.cpp -o SignalExample
./SignalExample

To terminate, press ctrl-c.

As you may suspect, the callback function is callback_sigint(). The callback function always has prototype as:

void signal_name (int signum);

The signum is a variable which hold the signal number we received. Thus, we can use a single signal handle to handle various signal sent. However this is beyond our league, but you should be able to figure it out.

If you are curious, the function signal has prototype:

void (*signal (int sig, void (*func)(int)))(int);

Handling a Signal using Registration and Handling Class

Now let’s see how can be implement the signal handling using Object Oriented Programming.

Here is our header file:

#ifndef __SIGNALHANDLER_HPP__
#define __SIGNALHANDLER_HPP__

#include <stdexcept>
using std::runtime_error

class SignalException : public runtime_error
{
public:
   SignalException(const std::string& _message)
      : std::runtime_error(_message)
   {}
};

class SignalHandler
{
protected:
    static bool mbGotExitSignal;

public:
    SignalHandler();
    ~SignalHandler();

    static bool gotExitSignal();
    static void setExitSignal(bool _bExitSignal);

    void        setupSignalHandlers();
    static void exitSignalHandler(int _ignored);

};
#endif

And this is our implementation:

#include <signal.h>
#include <errno.h>

#include "SignalHandler.hpp

bool SignalHandler::mbGotExitSignal = false;

/**
* Default Contructor.
*/
SignalHandler::SignalHandler()
{
}

/**
* Destructor.
*/
SignalHandler::~SignalHandler()
{
}

/**
* Returns the bool flag indicating whether we received an exit signal
* @return Flag indicating shutdown of program
*/
bool SignalHandler::gotExitSignal()
{
    return mbGotExitSignal;
}

/**
* Sets the bool flag indicating whether we received an exit signal
*/
void SignalHandler::setExitSignal(bool _bExitSignal)
{
    mbGotExitSignal = _bExitSignal;
}

/**
* Sets exit signal to true.
* @param[in] _ignored Not used but required by function prototype
*                     to match required handler.
*/
void SignalHandler::exitSignalHandler(int _ignored)
{
    mbGotExitSignal = true;
}

/**
* Set up the signal handlers for CTRL-C.
*/
void SignalHandler::setupSignalHandlers()
{
    if (signal((int) SIGINT, SignalHandler::exitSignalHandler) == SIG_ERR)
    {
        throw SignalException("!!!!! Error setting up signal handlers !!!!!");
    }
}

And let’s test it:

#include <iostream>
#include "SignalHandle.hpp"
using namespace std;

main()
{
  int iret;

  try
  {
    SignalHandler signalHandler;

    // Register signal handler to handle kill signal
    signalHandler.setupSignalHandlers();

    // Infinite loop until signal ctrl-c (KILL) received
    while(!signalHandler.gotExitSignal())
    {
        sleep(1);
    }

    iret = EXIT_SUCCESS;
  }
  catch (SignalException& e)
  {
    std::cerr << "SignalException: " << e.what() << std::endl;
    iret = EXIT_FAILURE;
  }
  return(iret);
}

To compile, use following commands:

g++ SignalHandle.cpp main.cpp -o Signal

Creating Own Signal Function

Now, let’s going deeper to learn how signal() function is implemented. We will try to mimic it by creating our own function which will behave like what signal() does. Let’s call it as regsignal().

The signal() is implemented using sigaction function. There is also a struct we need to fill, sigaction which allocate and fill.

#ifndef __REG_SIGNAL_HPP__
#define __REG_SIGNAL_HPP__

#include <signal.h>

/* for signal handler */
typedef void Sigfunc(int);

Sigfunc * regsignal(int signo, Sigfunc *func);

#endif

And the implementation

#include "RegSignal.hpp"

Sigfunc *
regsignal(int signo, Sigfunc *func)
{
	struct sigaction	act, oact;

	act.sa_handler = func;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	if (signo == SIGALRM) {
#ifdef	SA_INTERRUPT
		act.sa_flags |= SA_INTERRUPT;	/* SunOS 4.x */
#endif
	} else {
#ifdef	SA_RESTART
		act.sa_flags |= SA_RESTART;		/* SVR4, 44BSD */
#endif
	}
	if (sigaction(signo, &act, &oact) < 0)
		return(SIG_ERR);
	return(oact.sa_handler);
}
/* end signal */

A little trivia.  signal() is historical function that predates Posix.1 and different implementations provide different signal semantics when it is called. Posix has explicitly spells out the semantics and recommend to use sigaction() and sigaction structure.

Appendix A

Types of signals:

SIGHUP 1 Hangup (POSIX)Report that user’s terminal is disconnected. Signal used to report the termination of the controlling process.
SIGINT 2 Interrupt (ANSI)Program interrupt. (Ctrl-C)
SIGQUIT 3 Quit (POSIX)Terminate process and generate core dump
SIGILL 4 Illegal Instruction (ANSI)Generally indicates that the executable file is corrupted or use of data where a pointer to a function was expected.
SIGTRAP 5 Trace trap (POSIX)
SIGABRT SIGIOT 6 Abort (ANSI) / IOT trap (4.2 BSD) Process detects error and reports by calling abort.
SIGBUS 7 BUS error (4.2 BSD)Indicates an access to an invalid address.
SIGFPE 8 Floating-Point arithmetic Exception (ANSI)This includes division by zero and overflow.The IEEE Standard for Binary Floating-Point Arithmetic (ANSI/IEEE Std 754-1985) defines various floating-point exceptions.
SIGKILL 9 Kill, unblockable (POSIX)Cause immediate program termination. Can not be handled, blocked or ignored.
SIGUSR1 10 User-defined signal 1
SIGSEGV 11 Segmentation Violation (ANSI)Occurs when a program tries to read or write outside the memory that is allocated for it by the operating system, dereferencing a bad or NULL pointer. Indicates an invalid access to valid memory.
SIGUSR2 12 User-defined signal 2
SIGPIPE 13 Broken pipe (POSIX)Error condition like trying to write to a socket which is not connected.
SIGALRM 14 Alarm clock (POSIX)Indicates expiration of a timer. Used by the alarm() function.
SIGTERM 15 Termination (ANSI)This signal can be blocked, handled, and ignored. Generated by “kill” command.
SIGSTKFLT 16 Stack fault
SIGCHLD SIGCLD 17 Child status has changed (POSIX)Signal sent to parent process whenever one of its child processes terminates or stops.
SIGCONT 18 Continue (POSIX)Signal sent to process to make it continue.
SIGSTOP 19 Stop, unblockable (POSIX)Stop a process. This signal cannot be handled, ignored, or blocked.
SIGTSTP 20 Keyboard stop (POSIX) Interactive stop signal. This signal can be handled and ignored. (ctrl-z)
SIGTTIN 21 Background read from tty (POSIX)
SIGTTOU 22 Background write to tty (POSIX)
SIGURG 23 Urgent condition on socket (4.2 BSD)Signal sent when “urgent” or out-of-band data arrives on a socket.
SIGXCPU 24 CPU limit exceeded (4.2 BSD)
SIGXFSZ 25 File size limit exceeded (4.2 BSD)
SIGVTALRM 26 Virtual Time Alarm (4.2 BSD).Indicates expiration of a timer.
SIGPROF 27 Profiling alarm clock (4.2 BSD)Indicates expiration of a timer. Use for code profiling facilities.
SIGWINCH 28 Window size change (4.3 BSD, Sun)
SIGIOSIGPOLL 29 I/O now possible (4.2 BSD)Pollable event occurred (System V).

Signal sent when file descriptor is ready to perform I/O (generated by sockets)

SIGPWR 30 Power failure restart (System V)
SIGSYS 31 Bad system call

As seen on /usr/include/bits/signum.h

You can also list the signal available by invoking following command:

kill -l

Appendix B

Useful function:

  • signal – ANSI C signal handling
  • raise – sends a signal to the current process
  • strsignal – return string describing signal (GNU extension)
  • psignal – print signal message
  • sigaction – POSIX signal handling functions (see the coding example)
  • sigsetops – POSIX signal set operations
  • sigvec – BSD software signal facilities
  • alarm – set an alarm clock for delivery of a signal

Social media & sharing icons powered by UltimatelySocial