1

Is there any way to send a signal to a process (in Linux), that results in a termination of the process after going through the "atexit-functions" (in this case: void shutdownEngines())? Using "pkill name" does not work.

#include <cstdlib>
void shutdownEngines() {/*is not executed by "pkill name"*/}
int main() {
    atexit(shutdownEngines);
    while(true)
       doStuff();
}

Usage: I'm currently programming a robot. Every time I want to test it, I'll start the program and terminate it with "pkill name", but "shutdownEngines" isn't called and the robot keeps moving, falling off the table etc.

I know I could do "pkill name; ./shutdownEngines.sh", but this would be very bad style in my case (the numbers of the gpio pins connected to the engines are defined in a header file of the main program (the source code of the main program is not on the robot but on my computer). Making sure that there's always a "shutdownEngines.sh" program/script with the right pins on every robot would be very complicated.

Update

The following code works perfectly:

#include <iostream>
#include <csignal>
#include <cstdlib>
void signalHandler(__attribute__((unused)) const int signum) {
    exit(EXIT_FAILURE);
}
void driverEpilog() {
    std::cout << "shutting down engines...";
    //drv255(0,0);
}
int main() {
    signal(SIGTERM, signalHandler);
    atexit(driverEpilog);
    while(true)
        system("sleep 1");
}
Community
  • 1
  • 1
Volker Weißmann
  • 554
  • 1
  • 6
  • 24
  • 1
    It would help you if you get into the habit of reading the manual page – Ed Heal Oct 28 '16 at 19:30
  • When you send a signal to a process, (by default) the process dies without going through `exit()`, so the routines registered with `atexit()` are not called. You'd have to write a signal handler that goes through `exit()` — which isn't supported by the C standard, and even POSIX doesn't officially allow it (see [How to avoid using `printf()` in a signal handler](http://stackoverflow.com/questions/16891019/)) — mainly because there's no control over what the functions in the `atexit` handlers do. – Jonathan Leffler Oct 28 '16 at 19:30
  • http://stackoverflow.com/questions/7376228/linux-c-catching-kill-signal-for-graceful-termination – Cyclonecode Oct 28 '16 at 19:31
  • Call `exit(3)` in the signal handler or call `exit(3)` after detecting (`errno == EINT`) you have received a signal. – Luis Colorado Nov 03 '16 at 05:46

1 Answers1

4

from the man page of atexit:

Functions registered using atexit() (and on_exit(3)) are not called if a process terminates abnormally because of the delivery of a signal.

atexit is called when your main routine returns or when you call exit, not on a signal.

When you call pkill you're sending a SIGTERM signal. Handle this signal with signal or sigaction instead (define handlers on SIGTERM, SIGINT, SIGFPE, ...) to stop the engines before exiting your program.

Example lifted from GNU C library documentation:

void
termination_handler (int signum)
{
  struct temp_file *p;

  for (p = temp_file_list; p; p = p->next)
    unlink (p->name);  // don't delete files, stop your engines instead :)
}

int
main (void)
{
  …
  struct sigaction new_action, old_action;

  /* Set up the structure to specify the new action. */
  new_action.sa_handler = termination_handler;
  sigemptyset (&new_action.sa_mask);
  new_action.sa_flags = 0;

  sigaction (SIGINT, NULL, &old_action);
  if (old_action.sa_handler != SIG_IGN)
    sigaction (SIGINT, &new_action, NULL);
  sigaction (SIGHUP, NULL, &old_action);
  if (old_action.sa_handler != SIG_IGN)
    sigaction (SIGHUP, &new_action, NULL);
  sigaction (SIGTERM, NULL, &old_action);
  if (old_action.sa_handler != SIG_IGN)
    sigaction (SIGTERM, &new_action, NULL);
  …
}

(of course, no handler can handle the SIGKILL "signal", which tells the OS to remove your process from the active process list, without further notice!)

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219