You're using cicleProgram()
as your signal handler (despite it having the wrong type — it should take an int
argument). That means you never return from the signal handler until you type q
or Q
, and the system is probably blocking the signal until the first signal handler returns. So, you never get the second signal — it is blocked.
Use a separate signal handler function. See also What is the difference between sigaction()
and signal()
? and use sigaction()
in preference to signal()
.
And use int main(void)
— with at least the return type. Even the old (C99) version of the standard requires that, let alone the current (C11) standard. We've progressed to the 21st Century; don't code in 20th Century C!
See also How to avoid using printf()
in a signal handler? for information on what you can do in a signal handler.
Could I add some control in that "while" in order to evaluate the signal alarm and avoid the deadlock?
There are multiple problems with the original code, and not all possible problems were diagnosed. An additional problem was that if the alarm fired, there was nothing to set the alarm again, so the program falls into waiting until you type a character.
Here's some experimental code you play with:
#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static int duration = 2;
static volatile sig_atomic_t alarm_fired = 0;
static void alarm_handler(int signum)
{
//signal(SIGALRM, alarm_handler);
write(STDOUT_FILENO, "Signalled!\n", 11);
alarm_fired = signum;
alarm(duration);
}
static void cicleProgram(void)
{
int opcion = 0;
while (opcion != 'q' && opcion != 'Q')
{
signal(SIGALRM, alarm_handler);
alarm(duration);
if ((opcion = getchar()) == EOF)
clearerr(stdin);
if (alarm_fired)
{
alarm_fired = 0;
printf("Alarm!\n");
}
printf("c = %d\n", opcion);
}
}
static void actionProgram(void)
{
struct sigaction sa = { 0 };
sa.sa_handler = alarm_handler;
sa.sa_flags = 0;
sigfillset(&sa.sa_mask);
sigaction(SIGALRM, &sa, 0);
int opcion = 0;
while (opcion != 'q' && opcion != 'Q')
{
alarm(duration);
if ((opcion = getchar()) == EOF)
clearerr(stdin);
if (alarm_fired)
{
alarm_fired = 0;
printf("Alarm!\n");
}
printf("c = %d\n", opcion);
}
}
int main(void)
{
printf("Using signal (q to quit):\n");
cicleProgram();
printf("Using sigaction (q to quit):\n");
actionProgram();
return 0;
}
There are two active functions, each with a loop. The first is based on your original cicleProgram()
but the function has been revamped; it is no longer the signal handler. I am running on Mac OS X (BSD-based), and these systems do not require you to reset the signal()
handler in the signal handler function. The second function, actionProgram()
, uses sigaction()
instead of signal()
. It probably isn't necessary, but it gives you something to look at. The absence of SA_RESTART
in the sa.sa_flags
element means that the read()
system call reports that it was interrupted each time the signal goes off. The code in the signal_handler()
doesn't use disallowed function calls.
Example output (program name al97
):
$ ./al97
Using signal (q to quit):
Signalled!
Signalled!
Signalled!
Signalled!
WonderfulSignalled!
Alarm!
c = 87
c = 111
c = 110
c = 100
c = 101
c = 114
c = 102
c = 117
c = 108
c = 10
Signalled!
Signalled!
q
Alarm!
c = 113
Using sigaction (q to quit):
c = 10
Signalled!
Alarm!
c = -1
Signalled!
Alarm!
c = -1
Signalled!
Alarm!
c = -1
Signalled!
Alarm!
c = -1
ASignalled!
Alarm!
c = -1
lso workingSignalled!
Alarm!
c = -1
c = 65
c = 108
c = 115
c = 111
c = 32
c = 119
c = 111
c = 114
c = 107
c = 105
c = 110
c = 103
c = 10
qSignalled!
Alarm!
c = -1
c = 113
$
There were some quite long pauses in the run, but you can experiment on your machine. You may need to reinclude the signal()
in the alarm_handler()
function for cicleProgram()
and use a different handler (that doesn't use signal()
, as now) for actionProgram()
.