How to detect program termination in C/Linux? - c

How can an application find out that it just started terminating ? Can I use signal handler for that ?

Enable atexit(). It will call a function when program terminated normally.
Sample code:
#include <stdio.h>
#include <stdlib.h>
void funcall(void);
void fnExit1 (void)
{
printf ("Exit function \n");
}
int main ()
{
atexit (fnExit1);
printf ("Main function start\n");
funcall();
printf ("Main function end\n");
return 0;
}
void funcall(void)
{
sleep(2);
exit(0);
}
Output:
Main function start
Exit function

You Could try ---> int raise (int sig)
And handle when SIGTERM or SIGKILL is raised!!

You can also register a function to be called upon exit of a process. See man atexit

You can install a signal handler for SIGINT ,SIGKILL and SIGSEGV. In the signal handler you can take a stack dump so you can debug your application later.In the signal handler set the disposition of SIGINT ,SIGKILL and SIGSEGV back to default.

Related

Find signal handler function using GDB?

I am working on a C project that has bunch of files. Now I want to find the signal handler functions, but no success while surfing the project tree.
The first way I think about approaching this problem is running the binary with GDB.
Is there a way I can ask GDB to break as soon as a signal (e.g. Ctrl-C) is received?
Here is some reference:
http://nirbhay.in/2012/09/debug-signal-handlers-using-gdb/
Let's do some experiment with this program:
/*
#file : sig.c
*/
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void signalhandler(int signum) {
printf("\n SIGINT caught : %d", signum);
}
int main() {
signal(SIGINT, signalhandler);
while (1) {
printf("\n looping : inside main()");
sleep(1);
}
}
in this case you can do this way:
(gdb) handle SIGINT stop pass
after that, you step forward to get the signal handler function. Here I got:
$ gdb ./a
...
(gdb) handle SIGINT stop pass
SIGINT is used by the debugger.
Are you sure you want to change it? (y or n) y
Signal Stop Print Pass to program Description
SIGINT Yes Yes Yes Interrupt
(gdb) r
Starting program: /home/arc/a
looping : inside main()
looping : inside main()
^C
Program received signal SIGINT, Interrupt.
0x00007ffff7aef900 in __nanosleep_nocancel () from /usr/lib/libc.so.6
(gdb) s
Single stepping until exit from function __nanosleep_nocancel,
which has no line number information.
0x0000000000400596 in signalhandler(int) ()

Why signal handling is malfunctioning?

I have a signal handling snippet but it is somehow malfunctioning on my Mac and virtual Linux box at koding.com but on my office Linux PC it is working..Can someone please tell me why..
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void my_isr(int n){
printf("Hello World");
signal(SIGINT, SIG_DFL);
}
int main(){
signal(SIGINT, my_isr);
printf("pid = %d\n", getpid());
while(1);
return 0;
}
When I am pressing Ctrl+C it is not printing Hello World on the first time but it is re-modifying the SIGINT signal action & hence it is exiting the program when I press Ctrl+C second time. Can someone explain me why?
You are not allowed to call every function in a signal handler.
Read signal(7). Only async signal safe functions can be called (directly or indirectly) from a signal handler, and printf is not such a function. If you really want to reliably "print" something from inside a signal handler (which I don't recommend), you can only use the low-level write(2) syscall (it is async signal safe).
So you've got undefined behavior. This explains why it is so bad.
The recommended way is to set a volatile sigatomic_t flag in your signal handler, and to test it outside of it (e.g. in your while loop...).
And you forgot to call fflush(3). You might be more lucky by ending your printf format string with \n since stdout is line-buffered!
Of course, changing your printf inside your signal handler is still UB, even with a \n, but very often it would appear to work.
Here is a conforming version of your program....
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
volatile sig_atomic_t got_signal;
void my_sigint_handler (int signum) {
if (signum == SIGINT) // this is always true!
got_signal = 1;
#define INTERRUPT_MESSAGE "Interrupted!\n"
write(STDOUT_FILENO, INTERRUPT_MESSAGE, strlen(INTERRUPT_MESSAGE));
};
int main(int argc, char**argv) {
struct sigaction act_int;
memset (&act_int, 0, sizeof(act_int));
act_int.sa_handler = my_sigint_handler;
if (sigaction(SIGINT, &act_int, NULL)) {
perror("sigaction"); exit(EXIT_FAILURE);
};
printf ("start %s pid %d\n", argv[0], (int)getpid());
while (!got_signal) {
};
printf ("ended %s after signal\n", argv[0]);
return 0;
}
A useful (and permissible) trick could be to write(2) a single byte -inside your signal handler- on a pipe(7) to self (you set up that pipe using pipe(2) early at program initialization), and in your event loop poll(2) the read end of that pipe.
printf is the culprit just use counter in handler and print outside handler its value it will work.
use sigaction instead of signal

signal handler not working

I'm using czmq and zmq libraries in my code. I've registered a signal handler for SIGINT by calling signal in main. The code looks like this:
#include "czmq.h"
void sig_int(int signal);
void* pub_handler(){
zctx_t *context = zctx_new ();
void *publisher = zsocket_new (context, ZMQ_PUB);
zsocket_connect (publisher, "tcp://localhost:5555");
sleep(1);
char topic[20] = "REQ: speedlimit";
// while (true)
{
sleep( randof(10) );
zstr_sendm (publisher, topic);
zstr_send (publisher, "driver analysis data");
}
zctx_destroy (&context);
}
void* sub_handler(){
zctx_t *context = zctx_new();
void *subscriber = zsocket_new (context, ZMQ_SUB);
zsocket_connect (subscriber, "tcp://localhost:5557");
srandom ((unsigned) time (NULL));
char subscription [20] = "RESP: speedlimit" ;
zsocket_set_subscribe (subscriber, subscription);
while (true) {
char *topic = zstr_recv (subscriber);
if(!topic)
break;
char *data = zstr_recv (subscriber);
assert (streq (topic, subscription));
puts (topic);
puts (data);
free (topic);
free (data);
}
zctx_destroy (&context);
}
int main(int argc, const char *argv[])
{
pthread_t pub_id, sub_id;
signal (SIGINT, sig_int);
pthread_create(&pub_id, NULL, pub_handler, NULL);
pthread_create(&sub_id, NULL, sub_handler, NULL);
pthread_join(pub_id, NULL);
pthread_join(sub_id, NULL);
return 0;
}
void sig_int(int signal){
printf (" Interrupted\n");
exit(0);
}
compiled as gcc -o app app.c -lpthread -lczmq -lzmq.
The above code doesn't get into signal handler when ctrl+c interrupt is given.
what is the problem with czmq or zmq library and how it should be handled?
The documentation for zctx says that zctx sets up its own signal handler for SIGINT and SIGTERM, probably overriding your signal handler.
Sets up signal (SIGINT and SIGTERM) handling so that blocking calls
such as zmq_recv() and zmq_poll() will return when the user presses
Ctrl-C.
It also says that zctx is deprecated in favor of zsock, which doesn't appear to setup a signal handler according to its documentation. So my first suggestion is to use the new zsock socket API.
However, it seems that in both cases you can also call zsys_handler_set(NULL); (documented here) to explicitly disable the default SIGINT/SIGTERM handling in CZMQ.
PS: printf is not async-signal-safe, meaning that it should not be used in a signal handler. See here for a list of async-signal-safe functions in POSIX.
Got the solution after posting the question in zmq mailing list!!
Pieter Hintjens say's :: CZMQ does set up its own signal handling to trap SIGINT and SIGTERM.
You can disable this by calling
zsys_handler_set (NULL);
Adding the above line in my code disabled the signal handler setup by czmq and now I can use my own signal handler.
Thanks to Pieter Hintjens.
what is the problem ...
From man signal:
The effects of signal() in a multithreaded process are unspecified.
Use sigaction() instead.
I think your problem has nothing to do with CZMQ as such, and is caused by your threading. Specifically, the main thread is catching the signal, and the child thread is not. This is a common trap.
There are several solutions. What I'd perhaps do is sleep/wait in the main thread (you can e.g. use zmq_poll) and then when you get the signal, tell the child threads to end.
Some comments... if you are going to use CZMQ, then why not use its threading facilities, which wrap pthreads in a nicer interface. You have the older zthread class, and the newer zactor class.
I think your main program should be alive. Try this-
int main(int argc, const char *argv[])
{
pthread_t pub_id, sub_id;
signal (SIGINT, sig_int);
pthread_create(&pub_id, NULL, pub_handler, NULL);
pthread_create(&sub_id, NULL, sub_handler, NULL);
pthread_join(pub_id, NULL);
pthread_join(sub_id, NULL);
while(1); // Fix
}
You have changed the signal table using signal function.
signal (SIGINT, sig_int);
So whenever you will give SIGINT signal(ctrl+c), it will call the sig_int function. That is your signal handler. But in that function you are not killing any process.
So whenever you press ctrl + c, your program just call's the sig_int function, That function will print Interrupted for every SIGINT signal.
If you need your program want's to terminate when you press ctrl+c, don't modify the signal table like below.
signal (SIGINT, sig_int);
Instead of that
signal (SIGINT, SIG_DFL);
It will terminate your program, when you press ctrl+c.
Else you can try this also-
void sig_int(int signal){
signal (SIGINT, SIG_DFL); // here i am again changing the signal table to default.
printf (" Interrupted\n");
exit(0);
}
In this case, when you press ctrl+c first time it will call the sig_int function, but when you press second time it will terminate your program. because i have modified the signal table inside your sig_int function.

Make a signal switch the action of another signal

I am working in C language. I am trying to catch and process two different signals:
INT: when this signal is caught, action1 or action2 is triggered
QUIT: when this signal is caught, the INT signal action is switched (action1->action2 or action2->action1)
Default INT signal action is set to action1.
In my code,switchaction function is well triggered by QUIT signal, but has no effect on INT signal action :s
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
typedef void (*sighandler_t)(int);
sighandler_t prev_handler;
void action1(int n){
printf("First message\n");
}
void action2(int n){
printf("Second message\n");
}
void switchaction(int n){
printf("Switch action\n");
prev_handler=action2;
}
int main() {
prev_handler = action1;
printf("PID: %d\n", getpid());
prev_handler= signal(SIGINT,prev_handler);
signal(SIGQUIT,switchaction);
travail(); //This function never ends
}
Would you have any idea of what is wrong in my code ?
Thanks,
Yann
Your syscall
prev_handler= signal(SIGINT,prev_handler);
is setting the signal handler to the value of prev_handler variable at the moment you are executing the signal syscall. Changing (after) the value of prev_handler does not change the handling of SIGINT signal. In other words, signal (and most C calls) have a call by value semantics. If you call signal once, the kernel keep the same handler (till you call signal again with the same signal number, or till you call sigaction(2) etc...).
Read carefully (assuming you are on Linux) the signal(7) and signal(2) man pages.
I would instead define
volatile sig_atomic_t howhandle;
void switchaction(int n __attribute__((unused))) {
if (howhandle)
howhandle = 0;
else
howhandle = 1;
}
void handleint (int n) {
if (howhandle) action1(n); else action2(n);
}
and install just
signal(SIGINT, handleint);
signal(SIGQUIT, switchaction);
Also, notice that calling printf inside a handler is incorrect (because printf is not an async-signal-safe function, but you call it in action1, called by handleint...). Read again signal(7)
You should have some other volatile sig_atomic_t variables and test (and clear them) at appropriate places inside your travail working function, but set them only in your signal handlers. Setting a volatile sig_atomic_t variable is pretty much the only thing you can do reliably inside a signal handler.
If you accept Linux specific solutions learn more about signalfd(2) (and use also poll(2)...). Read also Advanced Linux Programming.

Handling multiple signals

I have a question about handling a signal.
Assume that if we recieve SIGINT signal, we should print "Recieved Signal". If within ten seconds the handler recieves another signal, it should print "Shutting Down" then exit with status 1.
I made my code like this:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void handler(int);
void secondhandler(int);
void alrmhandler(int);
void alrmhandler (int alrmsig)
{
alarm(0);
}
void secondhandler(int sig)
{
/* after recieving second signal prints shutting down and exit */
printf("Shutting Down\n");
exit(1);
}
void handler ( int sig )
{
/* recieve first SIGINT signal */
printf ("Recieved Signal\n");
/* handle for the alarm function */
signal(SIGALRM, alrmhandler);
/* start 10s alarm */
alarm(10);
/* catch second SIGINT signal within 10s*/
signal(SIGINT, secondhandler);
}
int main( void )
{
signal(SIGINT, handler);
printf( "Hello World!\n" );
for ( ;; )
{
/* infinite loop */
}
return 0;
}
I tried to compile it with dev c++, but it failed. Because SIGALRM undeclared(first use in this function).
Anyway, what I want to know is if this code is right. I actually kinda not sure with the alrmhandler(). should I ignore the SIGALRM?
If you are on a Windows platform, the only signals you will be able to send are : SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, or SIGTERM.
You write:
what I want to know is if this code is right.
Not entirely. printf() is not async-signal-safe, and so should not be called from within a signal handler unless you are very sure it is safe to do so. It is not safe to do so within the code you provide.
The alarm() technique is, generally, race-prone. Your ten second alarm might expire in the middle of your secondhandler() function. To guard against this, you might mask out signals to compensate with a more sophisticated signal manipulation function.
There are more elegant/flexible ways of implementing the timeout you desire, but that's perhaps a question better suited for codereview.stackexchange.com.

Resources