Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to exit a program gracefully without using pkill

Tags:

c++

linux

I am currently using a script to call pkill to terminate my C++ program. However i noticed that the destructors were not called from my traces when using pkill.

Is there another good way that i can exit the program gracefully?
pkill seems kind of untidy and some logs in the buffer do not get recorded. I'd like to be able to flush on my fstream and to close all resources programatically (instead of relying on the O/S to clean up my mess).

The application runs 24/7 without any problem, the only time i want to stop it is during maintenance. The application does not have any user interface for me to type exit.

like image 988
Angel Koh Avatar asked Jan 18 '12 07:01

Angel Koh


People also ask

Which signal gracefully terminate the process?

SIGTERM (signal 15) is used in Unix-based operating systems, such as Linux, to terminate a process. The SIGTERM signal provides an elegant way to terminate a program, giving it the opportunity to prepare to shut down and perform cleanup tasks, or refuse to shut down under certain circumstances.

Does exit kill a process?

exit() closes all files and sockets, frees all memory and then terminates the process.

What is kill Sigterm?

kill ends a process by sending it a signal. The default signal is SIGTERM. kill is a built-in shell command. In the tcsh shell, kill [-signal] %job|pid … sends the specified signal (or if none is given, the TERM (terminate) signal) to the specified jobs or processes.

What is Sigterm?

SIGTERM. (signal 15) is a request to the program to terminate. If the program has a signal handler for SIGTERM that does not actually terminate the application, this kill may have no effect. This is the default signal sent by kill.


3 Answers

You do it by defining a signal handler for SIGTERM along these lines:

Somewhere in your include block:

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

Yes, we're doing i C style!

Somewhere in the initialization part of your code:

signal (SIGTERM, handler);

and then define the signal handlers code (flush everything, etc):

void handler(int num) 
{
  // we might use this handler for many signals
  switch (num)
  {
    case SIGTERM:
      // clean up code.
      break;
  }
}

Now when you run pkill <app>, where <app> is the name of the executable, the code for handler() will run.

Without switches, the default SIGTERM signal will be sent to the application. Should you choose to use a different signal you would have to make sure you send the same signal as you "catch" in the handler().

Relevant information can be found by man 7 signal and of course, man kill.

like image 105
zrvan Avatar answered Oct 23 '22 03:10

zrvan


In addition to Zrvan's answer, be aware that only a restricted set of functions can be safely called from a signal handler. The signal(7) man page, and the Posix standards, require that only Async-signal-safe functions can be called directly or indirectly inside a signal handler. Note that printf or malloc are not safe inside a signal handler. Signal handler's code is tricky to write (and you cannot debug it easily, because signal sending is non-reproducible).

As the Glibc documentation suggests, your signal handler could just set a volatile sig_atomic_t variable, which your main loop[s] would test and handle.

You could also decide, if you application is event based, that some socket or named pipe is dedicated to control it. That event loop (perhaps using select(2) or poll(2), or even pselect or ppoll) could handle the control message on the pipe or socket.

You may be interested by event looping libraries like libevent. You might also use an HTTP server library like onion or Wt. You could also be interested by SNMP or D-bus.

A trick to overcome the limitation of signal handlers is to have them write on a pipe to the same process, as e.g. Qt's doc is suggesting. Then the event loop would handle reading on that pipe.

If your application is multi-threaded, signal handling is more tricky. Some signals are delivered to an individual thread.

like image 4
Basile Starynkevitch Avatar answered Oct 23 '22 03:10

Basile Starynkevitch


Unless you modify the target application, I don't see a way.

Consider the following:

int main()
{
   MyClass a;
   while ( true )
   {
   }
}

You'd have to tell the program to exit the loop. But unless you have some signal handling mechanism on your app, that seems impossible.

You'd need something like:

int main()
{
   MyClass a;
   while ( !killSignalReceived() )
   {
   }
}
like image 4
Luchian Grigore Avatar answered Oct 23 '22 04:10

Luchian Grigore