Signals and sleep not working properly - c

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.

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.

What's the return value of alarm() if there is already an alarm being set

In the Chapter 10 Signals of the APUE book, there is a sample code:
#include <signal.h>
#include <unistd.h>
static void sig_alrm(int signo) {
/* nothing to do, just return to wake up the pause */
}
unsigned int sleep1(unsigned int seconds) {
if (signal(SIGALRM, sig_alrm) == SIG_ERR)
return(seconds);
alarm(seconds); /* start the timer */
pause(); /* next caught signal wakes us up */
return(alarm(0)); /* turn off timer, return unslept time */
}
int main() {
sleep1(1);
return 0;
}
which simply implement an "imcomplete" sleep().
The book says that "This function looks like the sleep function, but this
simple implementation has three problems."
If the caller already has an alarm set, that alarm is erased by the first call to alarm. We can correct this by looking at alarm’s return value. If the number of seconds until some previously set alarm is less than the argument, then we should wait only until the existing alarm expires. If the previously set alarm will go off after ours, then before returning we should reset this alarm to occur at its designated time in the future.
We have modified the disposition for SIGALRM. If we’re writing a function for others to call, we should save the disposition when our function is called and restore it when we’re done. We can correct this by saving the return value from signal and resetting the disposition before our function returns.
There is a race condition between the first call to alarm and the call to pause. On a busy system, it’s possible for the alarm to go off and the signal handler to be called before we call pause. If that happens, the caller is suspended forever in the call to pause (assuming that some other signal isn’t caught).
I have some doubt about the above 3 statements:
Can somebody provide some example code for the statement1?
I don't know what the statement2 says, can someone give me robust explanation?
I don't know why statement3 will cause a race condition.
Thanks a lot!
to answer your question in the title.
The returned value is the number of seconds left in the prior call to alarm()
Your Q1:
int r1 = alarm(20);
printf("r1 = %d\n", r1);
int r2 = alarm(10);
printf("r2 = %d\n", r2);
This will usually print r1 = 0 and r2 = 20 because there was no alarm set at the first call and there were still 20 seconds left on the previous call at the second. At that point, there's 10 seconds left until the alarm goes off. There is only ever one alarm signal scheduled. You can't set alarms for 10 and 20 and 53 seconds hence; you can at most have one of these pending.
Your Q2:
If the code calling sleep1() already had a signal handler set to handle SIGALRM, you've thrown that information away. You should capture the return value from signal(SIGALRM, sig_alrm) and restore that when sleep1() is done. (It isn't clear what you should do if it was set to SIG_IGN.)
Your Q3:
Scheduling is not determinate. Your process could call alarm(1), and then be pre-empted. It could be more than a second before your program is rescheduled, and it will find that the alarm has gone off and handle the alarm before returning to executed pause(). Your call to pause() then will hang the program indefinitely because there is no alarm pending to wake it. You'll have to send a signal somehow.

c setitimer not sending signal when outside its call scope

i have the following case
void foo() {
printf("hi\n");
while(1);
}
int main(void)
{
struct sigaction temp;
temp.sa_handler = &foo;
sigfillset(&temp.sa_mask);
sigdelset(&temp.sa_mask, SIGVTALRM);
sigdelset(&temp.sa_mask, SIGINT );
sigaction(SIGVTALRM, &temp, NULL);
struct itimerval tv;
tv.it_value.tv_sec = 2; /* first time interval, seconds part */
tv.it_value.tv_usec = 0; /* first time interval, microseconds part */
tv.it_interval.tv_sec = 2; /* following time intervals, seconds part */
tv.it_interval.tv_usec = 0; /* following time intervals, microseconds part */
if (setitimer(ITIMER_VIRTUAL, &tv, NULL)){
perror(NULL);
}
while(1);
return 0;
}
all I want is that every 2 seconds foo will be called (foo actually does some other stuff other than while(1), just assume foo run takes more than 2 seconds), after 2 seconds foo is indeed called but then no other call is made untill foo returns. I tried playing with the signal masks (hence the sigfillset) but also when simply calling signal(SIGVTALRM, foo) no changes are made in the result. I also tried having the itimerval and the sigactions variables declared outside main and it didn't quite affect anything.
is the thing I'm trying to do even possible?
thanks!
reference: <http://www.gnu.org/software/libc/manual/html_node/Signals-in-Handler.html>
24.4.4 Signals Arriving While a Handler Runs
What happens if another signal arrives while your signal handler function is running?
When the handler for a particular signal is invoked, that signal is automatically blocked until the handler returns. That means that if two signals of the same kind arrive close together, the second one will be held until the first has been handled. (The handler can explicitly unblock the signal using sigprocmask, if you want to allow more signals of this type to arrive; see Process Signal Mask.)
However, your handler can still be interrupted by delivery of another kind of signal. To avoid this, you can use the sa_mask member of the action structure passed to sigaction to explicitly specify which signals should be blocked while the signal handler runs. These signals are in addition to the signal for which the handler was invoked, and any other signals that are normally blocked by the process. See Blocking for Handler.
When the handler returns, the set of blocked signals is restored to the value it had before the handler ran. So using sigprocmask inside the handler only affects what signals can arrive during the execution of the handler itself, not what signals can arrive once the handler returns.
Portability Note: Always use sigaction to establish a handler for a signal that you expect to receive asynchronously, if you want your program to work properly on System V Unix. On this system, the handling of a signal whose handler was established with signal automatically sets the signal’s action back to SIG_DFL, and the handler must re-establish itself each time it runs. This practice, while inconvenient, does work when signals cannot arrive in succession. However, if another signal can arrive right away, it may arrive before the handler can re-establish itself. Then the second signal would receive the default handling, which could terminate the process.
reference:<http://www.gnu.org/software/libc/manual/html_node/Process-Signal-Mask.html#Process-Signal-Mask>
24.7.3 Process Signal Mask
The collection of signals that are currently blocked is called the signal mask. Each process has its own signal mask. When you create a new process (see Creating a Process), it inherits its parent’s mask. You can block or unblock signals with total flexibility by modifying the signal mask.
The prototype for the sigprocmask function is in signal.h.
Note that you must not use sigprocmask in multi-threaded processes, because each thread has its own signal mask and there is no single process signal mask. According to POSIX, the behavior of sigprocmask in a multi-threaded process is “unspecified”. Instead, use pthread_sigmask.
Function: int sigprocmask (int how, const sigset_t *restrict set, sigset_t *restrict oldset)
Preliminary: | MT-Unsafe race:sigprocmask/bsd(SIG_UNBLOCK) | AS-Unsafe lock/hurd | AC-Unsafe lock/hurd | See POSIX Safety Concepts.
The sigprocmask function is used to examine or change the calling process’s signal mask. The how argument determines how the signal mask is changed, and must be one of the following values:
SIG_BLOCK
Block the signals in set—add them to the existing mask. In other words, the new mask is the union of the existing mask and set.
SIG_UNBLOCK
Unblock the signals in set—remove them from the existing mask.
SIG_SETMASK
Use set for the mask; ignore the previous value of the mask.
The last argument, oldset, is used to return information about the old process signal mask. If you just want to change the mask without looking at it, pass a null pointer as the oldset argument. Similarly, if you want to know what’s in the mask without changing it, pass a null pointer for set (in this case the how argument is not significant). The oldset argument is often used to remember the previous signal mask in order to restore it later. (Since the signal mask is inherited over fork and exec calls, you can’t predict what its contents are when your program starts running.)
If invoking sigprocmask causes any pending signals to be unblocked, at least one of those signals is delivered to the process before sigprocmask returns. The order in which pending signals are delivered is not specified, but you can control the order explicitly by making multiple sigprocmask calls to unblock various signals one at a time.
The sigprocmask function returns 0 if successful, and -1 to indicate an error. The following errno error conditions are defined for this function:
EINVAL
The how argument is invalid.
You can’t block the SIGKILL and SIGSTOP signals, but if the signal set includes these, sigprocmask just ignores them instead of returning an error status.
Remember, too, that blocking program error signals such as SIGFPE leads to undesirable results for signals generated by an actual program error (as opposed to signals sent with raise or kill). This is because your program may be too broken to be able to continue executing to a point where the signal is unblocked again. See Program Error Signals.
I know that this has been answered and accepted already but I made tiny changes to the OP's question as follows in accordance with my comments and had a successful result (foo being called every 2 seconds, ad infinitum)
Note that addition of the memset of the temp variable and the changing from SIGVTALRM to SIGALRM.
#include <stdio.h>
#include <sys/time.h>
void foo() {
printf("hi\n");
}
int main(int argc, char **argv)
{
struct sigaction temp;
memset(&temp, 0, sizeof(temp));
temp.sa_handler = &foo;
sigfillset(&temp.sa_mask);
sigdelset(&temp.sa_mask, SIGALRM);
sigdelset(&temp.sa_mask, SIGINT );
sigaction(SIGALRM, &temp, NULL);
struct itimerval tv;
tv.it_value.tv_sec = 2; /* first time interval, seconds part */
tv.it_value.tv_usec = 0; /* first time interval, microseconds part */
tv.it_interval.tv_sec = 2; /* following time intervals, seconds part */
tv.it_interval.tv_usec = 0; /* following time intervals, microseconds part */
if (setitimer(ITIMER_REAL, &tv, NULL)){
fprintf (stderr, "cannot start timer\n");
perror(NULL);
}
while(1) {
fprintf (stdout, "sleep 1\n");
sleep (1);
}
return 0;
}

how to use signals to print every specific time and generate keyboard interrupt?

I have the program below and I want to use signals to print the every 5 seconds, and handle keyboard interrupt like ctrl + c to terminate the process and ctrl + p to print the result.
int i=1;
while(i>0)
{
i++;
if(i%2==0)
{
printf("%d \n",i)
}
}
In my experience signal handling difficult to do reliably, prone to subtle race conditions and the like (and whoever thought EINTR was a good idea should be shot.) Then again I suppose I never really got the UNIX way of doing things.
My advise is to do as little work as humanly possible inside of the handlers themselves and to try to keep the signals masked anywhere you're not directly interested in them.
The following is my attempt at installing a SIGALRM handler and printing a message every 5 seconds:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/select.h>
// Raise a flag once the event occurs
volatile sig_atomic_t event;
void handler(int sig) { event = 1; }
int main(void) {
sigset_t mask;
// Install our alarm handler
struct sigaction action = { 0 };
action.sa_handler = handler;
sigaction(SIGALRM, &action, NULL);
// Mask out the alarm signal during normal operation to avoid races
// and having to handle EINTR everywhere
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
sigprocmask(SIG_SETMASK, &mask, &mask);
// Here goes the main loop..
for(;;) {
// Set the alarm
alarm(5);
// Wait for the alarm to happen with the alarm signal unblocked.
// Add whatever other I/O you're waiting for here
pselect(0, NULL, NULL, NULL, NULL, &mask);
// Did we get woken up by an alarm signal?
if(event) {
event = 0;
puts("Alarm!");
}
}
}
In your specific computationally-bound case I would suggest strategically polling the event flag from the loop instead of attempting to extract and print the present number from within the signal handler.
If you decide to go the latter route then beware that you cannot rely on being able to atomically read and write the value. Instead I would suggest a double-buffering scheme placing the two most recent values in a circular buffer with a (volatile sig_atomic_t) index pointing out the right slot. Oh, and you'll have to do the I/O through manual string manipulation and write() since printf is forbidden in a signal handler. The real kicker, though, is that you won't be able to synchronize with other standard output text in any sane fashion.
In essence using multithreading with a separate calculation thread is a far superior means of achieving the same end.

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.

Resources