Checking the last signal sent to your application - c

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.

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.

Signals and sleep not working properly

i have an assignment to make, for university, it is almost done, most thing working, there is just one aspect that is not working and i'm not quite sure how to fix it..
The objetivo is to make the problem wait for 2 ctrl+C and close.. But if he catch a first ctrl+C and pass more then 3 seconds the program must forget about it and wait again for another 2 ctrl+C. This is how i'm doing it:
/*Problem 2. Write a program that sleeps forever until the user interrupts it twice with a Ctrl-C, and
then exits. Once the first interrupt is received, tell the user: “Interrupt again to exit.”. The first
interrupt should be forgotten 3 seconds after it has occurred. Additionally, the program should block
the SIGQUIT signal, and ignore the SIGTSTP signal. The program should start by printing “Interrupt
twice with Ctrl-C to quit.” on the screen.*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
//handler to catch the first ctrl_c and ask user to do it another time(no reference to time limit)
void ctrl_c(int sig){
signal(sig, SIG_IGN);
printf("\nInterrupt again to exit.\n");
}
//handler for second ctrl_c. If called, program will end
void second_catch(int sig){
if(sig == SIGINT){
printf("\n");
exit(0);
}
}
//handler to always ignore ctrl_z
void ctrl_z(int sig){
signal(sig, SIG_IGN);
}
int main(){
//blocking SIQUIT (Ctrl+\) using series of command to change the mask value of SIGQUIT
sigset_t sg;
sigemptyset (&sg);
sigaddset(&sg, SIGQUIT);
sigprocmask(SIG_BLOCK, &sg, NULL);
//installing handler to ignore SIGTSTP (Ctrl+Z)
signal(SIGTSTP, ctrl_z);
//two part SIGINT handling
printf("\nInterrupt twice with Ctrl+C to quit.\n");
signal(SIGINT, ctrl_c); //first handler install
do{ //cycle for second hanler install and 3 second timer
if(sleep(3) == 0){
main(); //if second_catch handler is not called within 3 seconds, program will restart
}
else {
signal(SIGINT, second_catch); //upon call, program will end
}
}while(1);
return 0;
}
What's happening is that it keeps reseting after 3 seconds, in a loop.. But i want to reset only 1 time after i click ctrl+c and 3 seconds passed..
What must i change?
Your approach is unlikely to lead to a working program.
First, use a signal handler that only sets a global variable (of volatile sig_atomic_t type) whenever a SIGINT signal is caught. Do not try to print anything from the signal handler, as standard I/O is not async-signal safe.
Second, use sigaction() to install the signal handler. Use zero flags. In other words, do NOT use SA_RESTART flag when installing the handler. This way, when a signal is delivered to your handler, it will interrupt most syscalls (including sleeps). (The functions will return -1 with errno == EINTR.)
This way, after your main() has installed the signal handler, you can have it print the instruction, and enter into a loop.
In the loop, clear the interrupt flag, and sleep for a few seconds. It does not matter how long. If the interrupt flag is not set after the sleep completes, continue (at the beginning of the loop).
Otherwise, you know that the user has pressed Ctrl+C. So, clear the interrupt flag, and sleep for another three seconds. If the flag is set after the sleep completes, you know the user supplied another Ctrl+C, and you can break out of the loop. Otherwise, you just continue the loop again.
Technically, there is a race condition here, as the user might press Ctrl+C twice in a row, rapidly enough so that the main() only sees one.
Unfortunately, increments (flag++) are not atomic; the compiler or the hardware may actually do temp = flag; temp = temp + 1; flag = temp; and the signal may be delivered just before the third step, leading to the signal handler and main() seeing different values of flag.
One way around that is to use C11 atomics (if the architecture and C library provides them, in <stdatomic.h>, with macro ATOMIC_INT_LOCK_FREE defined): volatile atomic_int flag; for the flag, __atomic_add_fetch(&flag, 1, __ATOMIC_SEQ_CST) to increment it, and __atomic_sub_fetch(&flag, 1, __ATOMIC_SEQ_CST) to decrement it.
Another way would be to use a POSIX semaphore. The signal handler can increment it (using sem_post()) safely. In main(), you can use sem_timedwait() to wait for the signal for a limited time, and sem_trywait() to decrement it.
A third way would be to use sigtimedwait() to catch the signal in main() with a timeout, without any signal handlers. This last one is, I believe, the most robust and simple to implement, so that's what I'd use in a real application.
It turns out that there is another way to achieve this, one that responds to two consecutive Ctrl+C presses within three seconds, without leaving any nasty corner cases.
This is NOT exactly what was asked of OP, and as such is not a valid answer to their exercise, but this would be a good approach otherwise.
The idea is to use alarm() and a SIGALRM handler, and two sig_atomic_t flags: one that counts the Ctrl+C keypresses, and one that flags the case when there have been two in a three-second period.
Unfortunately, sleep() cannot be used in this case -- you have to use nanosleep() instead --, as sleep(), alarm(), and SIGALRM signal handling may interfere with each other.
Essentially, we use
#define INTR_SECONDS 3
static volatile sig_atomic_t done = 0;
static volatile sig_atomic_t interrupted = 0;
static void handle_sigalrm(int signum)
{
if (interrupted > 1)
done = 1;
interrupted = 0;
}
static void handle_sigint(int signum)
{
interrupted++;
if (interrupted > 1) {
done = 1;
alarm(1);
} else
alarm(INTR_SECONDS);
}
handle_sigalrm() is installed as the SIGALRM handler, with SIGINT in its signal mask; handle_sigint() is installed as the SIGINT handler, with SIGALRM in its signal mask. This way the two signal handlers block each other, and won't be interrupted by each other.
When a first SIGINT is received, the alarm is primed. If this is the second (or third etc.) SIGINT without an intervening SIGALRM, we also set the done flag, and prime the alarm to occur in one second, to ensure we catch the state change in at most one second.
When a SIGALRM is received, the interrupt count is zeroed. If it was two or more, the done flag is also set.
In main(), we only check done and interrupted, never modify them. This avoids the corner cases I was worried about.
In the worst case, there is one second delay to quitting, if the second Ctrl+C is delivered after we check, but just before we sleep. The alarm(1) in handle_sigint() is for just that case.
The loop in main is then just
while (!done) {
while (!done && !interrupted)
nanosleep(&naptime, NULL);
if (done)
break;
printf("Ctrl+C again to quit!\n");
fflush(stdout);
while (interrupted == 1 && !done)
nanosleep(&naptime, NULL);
}
The first inner loop only sleeps when it has been over three seconds since the last SIGINT (or we never received one). It will be interrupted by both SIGINT and SIGALRM, so the duration does not matter.
The if (done) break; case just avoids printing anything if the user had lightning hands and typed Ctrl+C twice really fast.
The second inner loop only sleep when we are waiting for a second Ctrl+C. It too will be interrupted by both signals, so the duration here does not matter either. Note, however, that we do wish to check interrupted first, to ensure we catch all changes reliably. (If we checked done first, we might be interrupted before we check interrupted, and it is possible, in theory, that done changes to nonzero and interrupt to zero and then to 1 in the mean time. But, if we check interrupted first, and it is 1, any additional interrupts will just set done, which we'll catch. So, interrupted == 1 && done == 0 is the correct check in the correct order here.)
As noted above, the duration specified for nanosleep() does not actually matter, as it will be interrupted by the signal delivery anyway. Something like ten seconds should be fine,
struct timespec naptime = { .tv_sec = 10, .tv_nsec = 0L };
If the lecturer had recommended POSIX.1 functions (sigaction(), nanosleep()), this would have been surprisingly interesting exercise.

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.

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

Signal handler for SIGALRM does not work even if resetting in the handler

The example code of section 10.6, the expected result is:
after several iterations, the static structure used by getpwnam will be corrupted, and the program will terminate with SIGSEGV signal.
But on my platform, Fedora 11, gcc (GCC) 4.4.0, the result is
[Langzi#Freedom apue]$ ./corrupt
in sig_alarm
I can see the output from sig_alarm only once, and the program seems hung up for some reason, but it does exist, and still running.
But when I try to use gdb to run the program, it seems OK, I will see the output from sig_alarm at regular intervals.
And from my manual, it said the signal handler will be set to SIG_DEF after the signal is handled, and system will not block the signal. So at the beginning of my signal handler I reset the signal handler.
Maybe I should use sigaction instead, but I only want to know the reason about the difference between normal running and gdb running.
Any advice and help will be appreciated.
following is my code:
#include "apue.h"
#include <pwd.h>
void sig_alarm(int signo);
int main()
{
struct passwd *pwdptr;
signal(SIGALRM, sig_alarm);
alarm(1);
for(;;) {
if ((pwdptr = getpwnam("Zhijin")) == NULL)
err_sys("getpwnam error");
if (strcmp("Zhijin", pwdptr->pw_name) != 0) {
printf("data corrupted, pw_name: %s\n", pwdptr->pw_name);
}
}
}
void sig_alarm(int signo)
{
signal(SIGALRM, sig_alarm);
struct passwd *rootptr;
printf("in sig_alarm\n");
if ((rootptr = getpwnam("root")) == NULL)
err_sys("getpwnam error");
alarm(1);
}
According to the standard, you're really not allowed to do much in a signal handler. All you are guaranteed to be able to do in the signal-handling function, without causing undefined behavior, is to call signal, and to assign a value to a volatile static object of the type sig_atomic_t.
The first few times I ran this program, on Ubuntu Linux, it looked like your call to alarm in the signal handler didn't work, so the loop in main just kept running after the first alarm. When I tried it later, the program ran the signal handler a few times, and then hung. All this is consistent with undefined behavior: the program fails, sometimes, and in various more or less interesting ways.
It is not uncommon for programs that have undefined behavior to work differently in the debugger. The debugger is a different environment, and your program and data could for example be laid out in memory in a different way, so errors can manifest themselves in a different way, or not at all.
I got the program to work by adding a variable:
volatile sig_atomic_t got_interrupt = 0;
And then I changed your signal handler to this very simple one:
void sig_alarm(int signo) {
got_interrupt = 1;
}
And then I inserted the actual work into the infinite loop in main:
if (got_interrupt) {
got_interrupt = 0;
signal(SIGALRM, sig_alarm);
struct passwd *rootptr;
printf("in sig_alarm\n");
if ((rootptr = getpwnam("root")) == NULL)
perror("getpwnam error");
alarm(1);
}
I think the "apue" you mention is the book "Advanced Programming in the UNIX Environment", which I don't have here, so I don't know if the purpose of this example is to show that you shouldn't mess around with things inside of a signal handler, or just that signals can cause problems by interrupting the normal work of the program.
According to the spec, the function getpwnam is not reentrant and is not guaranteed to be thread safe. Since you are accessing the structure in two different threads of control (signal handlers are effectively running in a different thread context), you are running into this issue. Whenever you have concurrent or parallel execution (as when using pthreads or when using a signal handler), you must be sure not to modify shared state (e.g. the structure owned by 'getpwnam'), and if you do, then appropriate locking/synchronization must be used.
Additionally, the signal function has been deprecated in favor of the sigaction function. In order to ensure portable behavior when registering signal handlers, you should always use the sigaction invocation.
Using the sigaction function, you can use the SA_RESETHAND flag to reset the default handler. You can also use the sigprocmask function to enable/disable the delivery of signals without modifying their handlers.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void sigalrm_handler(int);
int main()
{
signal(SIGALRM, sigalrm_handler);
alarm(3);
while(1)
{
}
return 0;
}
void sigalrm_handler(int sign)
{
printf("I am alive. Catch the sigalrm %d!\n",sign);
alarm(3);
}
For example, my code is runing in main doing nothing and every 3 seconds my program says im alive x)
I think that if you do as i done calling in the handler function alarm with value 3, the problem is resolved :)

Resources