Unix - Control C and Control Z signal pick up issues - c

I'm experimenting around with the signals offered in Unix. The two I'm focusing on at the moment is Ctrl+C and Ctrl+Z. I want to catch the signal, and display a message to the screen. I got most of it working. Like the message displays when either signal is pressed. However it seems to only work once. I want the message to display each time Ctrl+C or Ctrl+Z are pressed. Like a loop.
#include <stdio.h>
#include <signal.h>
void handler (int signal);
int main ()
{
if (signal(SIGINT, handler) == SIG_ERR)
{
write (2, "Error catching signal C \n",26);
}
if (signal(SIGTSTP, handler) == SIG_ERR)
{
write(2, "Error catching signal Z \n", 26);
}
pause();
}
void handler (int signal)
{
if (signal == SIGINT)
{
write(1, "CONTROLC \n", 11);
}
else if (signal == SIGTSTP)
{
write(1, "CONTROLZ \n", 11);
}
else
{
write(2, "error \n", 8);
}
main();
}
I attempted to use the main function so that it would restart the program again, but I'm assuming its calling main from within a signal so it behaves differently?

Whoa, don't do it that way. :)
What's happening here is that the SIGINT, for example, is masked (blocked) during the execution of the handler. So, re-invoking main from within the handler re-runs main with SIGINT blocked. Thus you see your handler fire only once per signal — it's blocked ever after. (Note that this blocking behavior is not guaranteed by signal, which is one reason you should use sigaction instead.)
The typical signal handler should do as little work as possible, using only async-signal-safe functions, if any. Think of the handler as an interruption to the ordinary flow of your process, a special asynchronous flow which can use its own stack if need be.
If you want the program to behave like a loop, code it like a loop:
static volatile sig_atomic_t flag_int;
static volatile sig_atomic_t flag_tstp;
static void handle_int(int s) { flag_int = 1; } /* register me with sigaction */
static void handle_tstp(int s) { flag_tstp = 1; } /* me, too */
...
while (1) {
pause();
if (flag_int) { printf("CONTROL C\n"); flag_int = 0; }
if (flag_tstp) { printf("CONTROL Z\n"); flag_tstp = 0; }
}

Don't call main() from your signal handler, as your program is now stuck in the signal handler, and it will not call another signal handler for the same signal again while the handler is running.
(That behavior can be changed if you use sigaction() instead of signal() though).
Also see what the pause() call does.
DESCRIPTION
pause() causes the calling process (or thread) to sleep until a signal is delivered that either terminates the process or causes the
invocation of a signal-catching function.
So, your pause(); calls waits until a signal is delivered, and then continues your program.
So, do e.g. this to keep your program running.
for(;;) {
pause();
}

Do not use signal(2), except possibly to set a given signal's disposition to SIG_DFL or SIG_IGN. Its behavior varies among different Unixes.
For portability (among POSIX systems) and better control, you should install user signal handlers via the sigaction(2) syscall. Among other things, that allows you to choose between one-shot and persistent mode when you install the handler.
If you are obligated to use signal(2), then your best bet is for the last thing the handler does to be to reinstall itself as the handler for the given signal (when that's in fact what you want).

Related

Why my sig_int() function can't prevent my function from exit in c?

The codes is as below, and is the same as the one in book apue3e:
#include "apue.h"
#include "sys/wait.h"
static void sig_int(int);
int
main(int argc, char *argv[]) {
pid_t pid;
char buf[MAXLINE];
int status;
if (signal(SIGINT, sig_int) == SIG_ERR) {
err_sys("signal error");
}
printf("%% ");
while (fgets(buf, MAXLINE, stdin) != NULL) {
if (buf[strlen(buf)-1] == '\n') {
buf[strlen(buf)-1] = '\0';
}
if ((pid = fork()) < 0) {
err_sys("fork error");
} else if (pid == 0) {
execlp(buf, buf, (char *)NULL);
err_ret("couldn't execlvp: %s\n", buf);
exit(127);
}
if ((pid = waitpid(pid, &status, 0)) < 0) {
err_sys("waitpid_error");
}
printf("%% ");
}
exit(0);
}
static void
sig_int(int signo/* arguments */) {
/* code */
printf("Interrupted\n%%3 ");
}
So, my question is why this signal handler doesn't handle the SIGINT signal and exit immediately after pressing the Ctrl+c which i was testing on archlinux.
[W]hy this signal handler doesn't handle the SIGINT signal and exit immediately after pressing the Ctrl+c which i was testing on archlinux.
Given
static void
sig_int(int signo/* arguments */) {
/* code */
printf("Interrupted\n%%3 ");
}
and
signal(SIGINT, sig_int)
Your process doesn't exit when you press CTRL-C for the simple reason your signal handler doesn't cause the process to exit.
You replaced the default SIGINT handler with your own, so the default action of exiting the process no longer happens.
Since you're running on Linux, I'll refer to the GNU glibc documentation on termination signals:
24.2.2 Termination Signals
These signals are all used to tell a process to terminate, in one way
or another. They have different names because they’re used for
slightly different purposes, and programs might want to handle them
differently.
The reason for handling these signals is usually so your program can
tidy up as appropriate before actually terminating. For example, you
might want to save state information, delete temporary files, or
restore the previous terminal modes. Such a handler should end by
specifying the default action for the signal that happened and then
reraising it; this will cause the program to terminate with that
signal, as if it had not had a handler. (See Termination in
Handler.)
The (obvious) default action for all of these signals is to cause the
process to terminate.
...
Macro: int SIGINT
The SIGINT (“program interrupt”) signal is sent when the user types
the INTR character (normally C-c).
The Termination in Handler glibc documentation states:
24.4.2 Handlers That Terminate the Process
Handler functions that terminate the program are typically used to
cause orderly cleanup or recovery from program error signals and
interactive interrupts.
The cleanest way for a handler to terminate the process is to raise
the same signal that ran the handler in the first place. Here is how
to do this:
volatile sig_atomic_t fatal_error_in_progress = 0;
void
fatal_error_signal (int sig)
{
/* Since this handler is established for more than one kind of signal,
it might still get invoked recursively by delivery of some other kind
of signal. Use a static variable to keep track of that. */
if (fatal_error_in_progress)
raise (sig);
fatal_error_in_progress = 1;
/* Now do the clean up actions:
- reset terminal modes
- kill child processes
- remove lock files */
…
/* Now reraise the signal. We reactivate the signal’s
default handling, which is to terminate the process.
We could just call exit or abort,
but reraising the signal sets the return status
from the process correctly. */
signal (sig, SIG_DFL);
raise (sig);
}
Also, note that there can be significant differences between signal() and sigaction(). See What is the difference between sigaction and signal?
Finally, calling printf() from with a signal handler is undefined behavior. Only async-signal-safe functions can be safely called from within a signal handler. See POSIX 2.4 Signal Concepts for the gory details.

Can't catch more than one interrupt

I want my program to run in a loop until it receives an alarm signal, in the meantime I want to run some code every time it receives an interrupt signal.
The following almost works:
bool volatile waiting = true;
bool volatile interrupted = false;
void catch_interrupt(int x)
{
interrupted = true;
}
void catch_alarm(int x)
{
waiting = false;
}
void alive()
{
signal(SIGINT, catch_interrupt);
signal(SIGALRM, catch_alarm);
alarm(10);
while (waiting)
{
if (interrupted)
{
printf("interrupted\n");
interrupted = false;
}
}
printf("done\n");
}
The problem is that it only works for the first interrupt signal. The second interrupt kills the program (without printing "done") regardless.
So the output I see is
^Cinterrupted
^C
when I want to see
^Cinterrupted
^Cinterrupted
done
Do not use signal() to install custom signal handlers, as its behavior in that case varies across implementations. In particular, on some systems, if signal() is used to set a custom signal handler for a given signal, then that signal's disposition is reset when the signal is received. That's what you seem to be observing, but you cannot portably rely on it.
Instead, install signal handlers via sigaction(). Among other things, it has a mechanism for specifying whether the handler should be reset upon receipt of the signal.
Signal handlers set with signal() are disarmed when the signal handler is called in response to a signal. You have to rearm the signals each time:
void catch_interrupt(int x)
{
interrupted = true;
signal(SIGINT, catch_interrupt);
}
void catch_alarm(int x)
{
waiting = false;
signal(SIGALRM, catch_alarm);
}
Yes, that means there is a small window of vulnerability when the first signal has been handled but the handler has not yet been reinstated when a second signal will cause the program to react as if no signal handler is installed (because no signal handler is installed).

How to make two processes signalling each others continuously?

I want to simulate a game server that should continuously send and receive signals with its parent. The scenario is as follows:
Parent sends signal to game.
Game catches the signal and sends a signal to the parent.
Parent catches the signal and sends again a signal to game.
and so on...
The problem is that the stops receiving or sending after the first lap:
static int game_s;
void game()
{
printf("game\n");
signal(SIGUSR1,game);
sleep(1);
kill(getppid(),SIGUSR1);
pause();
}
void parent()
{
printf("parent\n");
signal(SIGUSR1,parent);
sleep(1);
kill(game_s,SIGUSR1);
pause();
}
void main()
{
game_s = fork();
if(game_s>0)
{
signal(SIGUSR1,parent);
sleep(1);
kill(game_s,SIGUSR1);
pause();
}
else
{
signal(SIGUSR1,game);
pause();
}
}
The output is the following:
game
parent
Why it stopped here? Shouldn't the game server catch parent's signal and print "game" again...
By default the reception of a specific signal is blocked from the moment a process received this specific signal until the related signal handler had been left.
From man 3 signal:
void (*signal(int sig, void (*func)(int)))(int);
[...]
When a signal occurs, and func points to a function, it is implementation-defined whether the equivalent of a:
signal(sig, SIG_DFL);
is executed or the implementation prevents some implementation-defined set of signals (at least including sig) from occurring until the current signal handling has completed.
To change this behaviour establish the signal handling via sigaction() instead of signal() (which one should do any ways for portability reasons).
sigaction() takes a struct sigaction. The member sa_flags of the latter should have SA_NODEFER set.
From Linux' man 2 sigaction:
SA_NODEFER
Do not prevent the signal from being received from within its own signal handler. This flag is meaningful only when establishing a signal handler.
POSIX words this differently:
SA_NODEFER
If set and sig is caught, sig shall not be added to the
thread's signal mask on entry to the signal handler
unless it is included in sa_mask. Otherwise, sig shall
always be added to the thread's signal mask on entry to
the signal handler.
Be aware that each signal handler gets it's own stack allocated each time it gets invoked, so sooner or later this recursive ping-pong ends up in an out-of-memory condition.
Use message queues, or shared memory to do this. As stated above, this will eventually run out of memory and it will crash.

Gracefully Exiting a C Application

I currently have a program I have written in C on a server that has an infinite loop that processes information, each loop takes about 5 minutes to complete. I would like to have the following functionality in a shell script:
Terminate C program
Make source
Run program
The problem is, I don't know how to tell my C program to exit without doing something like ctrl+c, I would rather it finished processing the information it is currently working on before terminating itself.
The POSIX standard way to tell a process to finish its business and exit cleanly is to send it a SIGTERM signal. Depending on your application it may or may not be appropriate to exit on SIGINT, which is meant to interrupt a process, not terminate it. (Control-c sends SIGINT.)
Try putting a flag in your tight loop; check the flag at a time when it is easy to exit, but still frequently enough to exit promptly. In your case, receipt of a SIGTERM might put a message on the system log right away, then promise to exit within the next 5 minutes.
Your signal handler will look like this:
static int signalled; // if nonzero, what signal have we been sent?
static void SignalHandler(int signum) {
signalled = signum;
}
I check the global static variable signalled after every I/O operation, which means many times per second.
Here's my code to catch and restore signals:
static __sighandler_t sh, si, st;
static void catch_signals(void) {
if ((sh = signal(SIGHUP, SignalHandler)) == SIG_IGN) signal(SIGHUP, SIG_IGN);
if ((si = signal(SIGINT, SignalHandler)) == SIG_IGN) signal(SIGINT, SIG_IGN);
if ((st = signal(SIGTERM, SignalHandler)) == SIG_IGN) signal(SIGTERM, SIG_IGN);
signalled = 0;
}
static void restore_signals(void) {
signal(SIGHUP, sh);
signal(SIGINT, si);
signal(SIGTERM, st);
}
(This code is from a library, so I'm being extra careful to leave things the way I found them.)
Bonus trick: when time expires (this is a TV recording library), the timer just sets signalled = SIGTERM, and the same logic is used to exit the recorder normally.
like ctrl+c, I would rather it finished processing the information it
is currently working on before terminating itsel
Establish a signal handler for SIGINT or whatever you want and do your cleanup after you receive it. You shouldn't do the cleanup in the handler itself however.
volatile sig_atomic_t do_cleanup = 0;
void handler(int sig)
{
do_cleanup = 1;
}
Then in your main loop you just have to test do_cleanup and exit when you please. You must also be careful in properly treating EINTR errors if you're not already doing so.
Here is how to send signal from shell:
http://bash.cyberciti.biz/guide/Sending_signal_to_Processes
or simply man kill
Here is how to react to signal:
http://www.cs.cf.ac.uk/Dave/C/node24.html#SECTION002400000000000000000

on_exit and CTRL+C

I've got a small program that opens a file and does some operation on it. I subscribed the file closure to the program termination as follows:
static
void exit_handler (int ev, void *arg)
{
fprintf(stderr, "bye %d\n", WEXITSTATUS(ev));
fclose((FILE *)arg);
}
int main (int argc, char *argv[])
{
FILE *out;
...
out = fopen(argv[1], "wt");
if (out == NULL) {
perror("Opening output file");
exit(EXIT_FAILURE);
}
on_exit(exit_handler, out);
...
}
Trying to execute this I notice that it works properly only if the program terminates normally. In case of CTRL+C (SIGINT) the exit_handler callback is not executed.
Isn't that weird? Should I associate a exit(EXIT_FAILURE) call to the signal handler for SIGTERM? What is the best practice in this case?
on_exit will not be invoked for SIGTERM signals. You need to add a handler for it with signal. For example:
void signalHandler(void)
{
...
}
int main(void)
{
signal(SIGTERM, signalHandler);
}
Also note that SIGKILL can not be caught by design.
First of all, on_exit isn't specified by POSIX (atexit with the same semantics is). Second , the linux manual says:
The on_exit() function registers the given function to be called
at normal process termination, whether via exit(3) or via return from
the program's main().
Getting killed by a signal is not a normal exit for a process so callbacks installed with on_exit and atexit aren't implicitly called.
No, and in fact what you want is impossible. The signal generated by Ctrl+C is asynchronous, meaning it could occur between any two machine instructions in your program depending on when Ctrl+C is hit. As such, unless your program is thoroughly avoiding calling async-signal-unsafe functions anywhere in the main program flow, it's illegal to call async-signal-unsafe functions from the signal handler. exit is async-signal-unsafe, as is most of the default cleanup activity it does (like flushing/closing open files). I would expect the atexit function you want to register (atexit, not on_exit, is the correct name for this function) is also going to want to do async-signal-unsafe things.
If you need to perform cleanup when exiting based on a signal, you need to install a signal handler that does not exit itself, but instead sets a global volatile flag that your main program flow will later inspect (and exit if it's true).
From man page of on_exit,
The on_exit() function registers the given function to be called at
normal process termination, whether via exit(3) or via return from the
program's main().
So you need to explicity hook up a handler for SIGTERM using specific functions from signal.h
Something on the lines of
struct sigaction action;
memset (&action, 0, sizeof(action));
action.sa_handler = sigterm_handler;
if (sigaction(SIGTERM, &action, 0))
{
perror ("sigaction");
return 1;
}
/* SIGTERM handler. */
static void sigterm_handler (int sig)
{
...
}

Resources