Help with implementing signal handlers via signal() - c

void main ()
{
int c;
signal (SIGINT, Handle);
while (( c = getchar()) != '\n' );
return();
}
void Handle(signum)
{
signal {SIGINT, Handle);
printf ("beep \n");
}
I thought it would print 'beep' until any key has been pressed but the method call is outside the loop? :S

You register Handle() as handler for SIGINT. Signal SIGINT is sent when the user tries to interrupt the program, so if you start this program it should print beep if you press control-c.
See some documentation about SIGINT, about the signal() function and about using it.
As Tim points out below, use sigaction() instead of signal().

Handle is only called when an INT signal is delivered to the code (most likely when you press CTRLC or CTRLBREAK although there are other ways to raise that signal), not continuously while waiting for a keypress.
You'll also find that the lines
signal {SIGINT, Handle);
and
return();
are typos - that first brace should be a parenthesis and you should use return 0; for the second. In addition, main should return an integer if you want to be standards-compliant.

Besides using sigaction...
Please change the callback to NOT call printf. Printf calls system call write() and writes to the standard out buffer, mixing with the main's calls. Both system calls and modifying stdout should be avoided in a signal handler.
Instead, set a sig_atomic_t flag variable in the signal handler, and then check and unset it and do the printf in the main loop.

Related

why signal() function in C only works once

Here is my code:
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<setjmp.h>
void sighandler(int signum);
jmp_buf buf;
void main(){
signal(SIGINT,sighandler);
if(!setjmp(buf))
printf("welcome to this game\n");
int a = 1;
printf("raw value of a is %d\n",a);
printf("modify a:");
scanf("%d",&a);
printf("new value of a is %d\n",a);
}
void sighandler(int signum){
if(signum == SIGINT){
printf("\nyou can't quit this game by ctrl+C,now we will restart it\n");
longjmp(buf,1);
}
}
and I ran it on ubuntu,result like below:
welcome to this game
raw value of a is 1
input num to modify a:^C
you can't quit this game by ctrl+C,now we will restrat it
raw value of a is 1
input num to modify a:^C
It seems signal() only capture the SIGINT for the first time. I read some answers on site such as:
"when a signal is delivered, it is also blocked during execution of the handler (no SIGINT will be delivered while execution is in sigint_handler if it is called from SIGINT delivery);"
BUT I don't get it since my signal_handler function should exit quickly.
I don't know why is blocked.And is there any ways to make it work second or thrid time ? Thx
Inside your signal handler, SIGINT is blocked, that is, it is added to your process’ signal mask. (1)
When you leave the signal handler with longjmp, a non-local goto, the signal mask is untouched. Thus, when you resume execution at the setjmp point, you retain the signal mask set by your handler. (2)
sigsetjmp and siglongjmp address this issue by saving and restoring the signal mask.
However, I’d recommend reworking your code to avoid non-local gotos altogether. They can be used safely, but are easy to misuse and difficult to reason about.
Notes:
This behavior of signal is common, but not universal, which is one good reason to prefer the standardized sigaction to signal.
If you returned normally from your handler, the system would reset the mask for you.
You aren't actually returning from the signal handler (sure, you exit it, but you don't return from it -- you just jump to another context). If you let the signal handler return, your code will continue execution where it left off and it'll intercept any subsequent SIGINT signals the way you intend for it to.

Unix - Control C and Control Z signal pick up issues

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).

Checking the last signal sent to your application

I want to be able to break out of the while loop when a signal is sent. I'm unsure how to accomplish this without using a global variable or writing to a file. Would my best bet to be using a semaphore?
#include <stdio.h>
#include <signal.h>
void random()
{
printf("random!");
}
int main(void) {
signal(SIGINT, random);
// I want this while loop to break if random executes
while (1)
{
pause();
}
// do more stuff after loop
return 0;
}
pause blocks until a signal is received that calls a signal handler, so you could just add a break; after the pause(); to exit the loop. So you might as well get rid of the loop altogether.
If what you want to do is NOT wait, but instead loop doing something and only exit when the signal occurs, you can't use pause. The obvious way is to use a global variable, but you say you want to avoid that. An alternative that isn't really any simpler is to use sigprocmask/sigpending instead of a signal handler:
int main()
{
setset_t signals;
sigemptyset(&signals);
sigaddset(&signals, SIGINT);
sigprocmask(SIG_BLOCK, &signals, 0); /* block SIGINT */
while (1) {
/* do stuff */
sigpending(&signals);
if (sigismember(&signals, SIGINT)) {
/* got a SIGINT */
break;
}
}
}
Your main function isn't doing anything after the loop, except exiting. I understand this may be simplified code to ask the question. But if you're actually not doing anything after the loop you want to break from, then just change your sig handler function to this:
void random(int sig)
{
printf("random!");
exit(sig); // or exit(0); as in your main()
}
On the other hand, if you need to communicate between random (handler) and main then why are you reluctant to use a variable?
The correct answer really depends on what you're going to be doing in the loop. I'll assume pause() is simply fake code as an example since it's not useful.
If your loop is an event loop that waits with select or poll, you could switch to pselect (standard in POSIX) or ppoll (a nonstandard extension, but better since the select API is so bad) that which will also let you wait for signals. But you're still stuck with how to get the notification that the signal occurred. With just one signal, you could use the fact that EINTR was returned to infer that SIGINT happened, but this doesn't work so well if there could be other signal handlers too. Basically, signal handling is fundamentally global, and as such, global variables/global state have to be involved in some way. You could store a flag that the signal happened in a global variable and check it each time pselect/ppoll returns, or you could just stick with plain standard poll and use the self-pipe trick since you need to be doing something with global state in your signal handler anyway.
If your loop is not waiting for events but constantly spinning (e.g. a computational loop) then just blocking the signal (with sigprocmask or pthread_sigmask) and periodically checking for it with sigispending or sigwaitinfo is a simple solution that doesn't require any code in the signal handler.

signal always ends program

Doing homework with signals and fork and have a problem with the signal.
I've created the function:
void trata_sinal_int() {
char op[2];
printf("\nTerminate? (y/n)\n");
scanf("%s", op);
if (op[0] == 'y') {
printf("Bye Bye\n");
exit(0);
}
}
And in main I have:
signal(SIGINT, trata_sinal_int);
When I run this, and press CTRL ^C the function void trata_sinal_int() is called and I got the message.
If I press y program ends as expected but if I press n program still ends.
It is not returning to were he was before pressing CTRL ^C.
Is this supposed to happen?
It depends on which standard you are adhering to, but Standard C doesn't allow you to do much more than modify a variable of type volatile sig_atomic_t or call _Exit (or abort() or signal()) from a signal handler. POSIX is a lot more lenient. Your code in your signal handler, replete with user interaction, is pushing beyond the limits of what even POSIX allows. Normally, you want your signal handler function to be small and svelte.
Note that the signal handler function should be:
void trata_sinal_int(int signum)
{
This allows you to compile without casts or compiler warnings about type mismatches.
The signal() function may reset the signal handler back to default behaviour when it is invoked; classically, it is necessary to reinstate the signal handler inside the signal handler:
signal(signum, trata_sinal_int);
So far, that's all pretty generic and semi-trivial.
When you type the Control-C, the system does go back to roughly where it was when the signal was originally received. However, what happens next depends on where it was (one of the reasons you have to be so very careful inside the handler). For example, if it was in the middle of manipulating the free list pointers inside malloc(), it would return there, but if you'd reinvoked malloc() inside the handler, all hell might be breaking loose. If you were inside a system call, then your call may be interrupted (return with an error indication and errno == EINTR), or it may resume where it left off. Otherwise, it should go back to where the calculation was running.
Here's (a fixed up version of) your code built into a test rig. The pause() function waits for a signal before returning.
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
static void trata_sinal_int(int signum)
{
char op[2];
signal(signum, trata_sinal_int);
printf("\nTerminate? (y/n)\n");
scanf("%s", op);
if (op[0] == 'y')
{
printf("Bye Bye\n");
exit(0);
}
}
int main(void)
{
signal(SIGINT, trata_sinal_int);
for (int i = 0; i < 3; i++)
{
printf("Pausing\n");
pause();
printf("Continuing\n");
}
printf("Exiting\n");
return(0);
}
I should really point out that the scanf() is not very safe at all; a buffer of size 2 is an open invitation to buffer overflow. I'm also not error checking system calls.
I tested on Mac OS X 10.7.5, a BSD derivative. The chance are good that the resetting of signal() would be unnecessary on this platform, because BSD introduced 'reliable signals' a long time ago (pre-POSIX).
ISO/IEC 9899:2011 §7.14.1.1 The signal function
¶5 If the signal occurs other than as the result of calling the abort or raise function, the
behavior is undefined if the signal handler refers to any object with static or thread
storage duration that is not a lock-free atomic object other than by assigning a value to an
object declared as volatile sig_atomic_t, or the signal handler calls any function
in the standard library other than the abort function, the _Exit function, the
quick_exit function, or the signal function with the first argument equal to the
signal number corresponding to the signal that caused the invocation of the handler.
Furthermore, if such a call to the signal function results in a SIG_ERR return, the
value of errno is indeterminate.252)
252) If any signal is generated by an asynchronous signal handler, the behavior is undefined.
The references to quick_exit() are new in C2011; they were not present in C1999.
POSIX 2008
The section on Signal Concepts goes through what is and is not allowed inside a signal handler under POSIX in considerable detail.
First, your signal handler is not exactly async signal safe. In practice this is probably not a problem in your case, since I assume the main() is basically doing nothing while it is waiting for the signal. But it is definately not correct anyway.
As for why the program exits, not counting segfault:s in the signal handler due to invalid use of FILE* functions such as printf, sscanf etc, when the signal is received any system calls you are doing (or, well, most) will be interreupted with EAGAIN.
If you are using something like sleep() in main to wait for the signal to occur it will be interrupted. You are expected to restart it manually.
To avoid this you probably want to use the significantly more portable sigaction interface instead of signal. If nothing else this allows you to indicate that you want system calls to be restarted.
The reason that FILE * functions (and most other functions that use global state such as malloc and free) is not allowed in signal handlers is that you might be in the middle of another operation on the same state when the signal arrives.
This can cause segfaults or other undefined operations.
The normal 'trick' to implement this is to have a self-pipe: The signal handler will write a byte to the pipe, and your main loop will see this (usually by waiting in poll or something similar) and then act on it.
If you absolutely want to do user interaction in the signal handler you have to use write() and read(), not the FILE* functions.

What is the difference between normal function call and signal() system call?

While learning signal() system call, I supposed to come across the following code,
#include <stdio.h>
#include <signal.h>
void sigproc(int);
void quitproc(int);
int main(int argc,char **argv)
{
signal(SIGINT, sigproc); //Is it like a normal Call to signal()?
signal(SIGQUIT, quitproc);// This too?
printf("ctrl- c disabled use ctrl\ to quit \n");
while(1);
return 0;
}
void sigproc(int signo)
{
printf("you have pressed ctrl - c \n");
}
void quitproc(int signo)
{
printf("U cant quit\n");
// exit(0);
}
I am calling the function signal() twice in main(). But its executed only when I'm pressing Ctrl-C and Ctrl-\ keys. I thought its also like normal function call. What is actually happening in the signal handler functions?
The signal function establishes a signal handler. What it means: "When my process receives this signal, run this function instead of doing whatever the default was".
So, in your example the calls to signal don't call the function. To actually see the signals in action, do this:
Start your process in one terminal
From another terminal:
kill -INT `pidof proc`
As a side note, printf and friends aren't async-signal-safe. It might come as a shocker, but it's unsafe to use them in signal handlers.
As a side side note, even if you tagged your question Unix it's important to know that signals (and the signal function) are standard, integral parts of C. Signal handling and the signal function are described in C99 in §7.14.1.

Resources