how to stop or jump signal and go to main? - c

What should i add to code to stop the signal and return to Main?
Do not use '() exit', i want to end or jump signal and go to main fuction.
i try to branch. but it's not works.
main{
void countdown(int);
signal (SIGALRM, countdown);
....
....
....
}
void countdown(int signum)
{
static int num =10;
printf("%d..",num--);
fflush(stdout);
if (num <0){
printf("DONE");
exit(0); // i want to change do not use exit() and get out this signal
}
}

You cannot invoke any of the functions you use from a signal handler. Only functions from man signal-safety list.
For the purpose of displaying progress indicator instead of using alarm/SIGALRM you may like start another thread that uses nanosleep to wait till the next tick and then print progress status.

signal invokes asynchronously a function when a call is received. When the called function (countdown here) terminates, it return right in the place left when the signal was caught.
So here, I'll say you just have to remove exit(0); and let the nature do the rest.

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.

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

Help with implementing signal handlers via signal()

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.

Resources