Is there a difference between "I/O block status" and "sleep"? - c

Can SIGCONT wake up the sleeping process?
I learned the day before yesterday that signal handlers fail the "sleep" of the process.
In the same way, I tried to fail "read" with a signal handler.
The code is as follows.
#include <signal.h>
#include <unistd.h>
void signal_handler(int signo)
{
write(1, "\nI've got signal\n", 17);
return;
}
int main()
{
char buf[10];
signal(SIGINT, signal_handler);
read(0, buf, 1);
write(1, buf, 1);
return 0;
}
However, after the signal handler was carried out, the process went back into I/O block state.
The following code was also executed for re-verification.
#include <signal.h>
#include <unistd.h>
void signal_handler(int signo)
{
write(1, "\nI've got signal\n", 17);
return;
}
int main()
{
char buf[10];
signal(SIGINT, signal_handler);
sleep(100);
write(1, "awake", 5);
return 0;
}
In this case, after receiving the signal handler, the process was no longer asleep.
Is there a way to get out of the blocked state after receiving the signal and continue the process? (with the input failed)

According to documentation of signal() function:
The behavior of signal() varies across UNIX versions, and has also
varied historically across different versions of Linux. Avoid its
use: use sigaction(2) instead. See Portability below.
...
Portability
The only portable use of signal() is to set a signal's disposition to
SIG_DFL or SIG_IGN. The semantics when using signal() to establish a
signal handler vary across systems (and POSIX.1 explicitly permits
this variation); do not use it for this purpose.
Thus, you should use sigaction() instead of signal().
If you replace signal() with sigaction() in your program it should work as expected.

Related

make open() return when signal is caught

When I call open("./fifo",O_RDONLY), the syscall will block because no one is writing to the fifo ./fifo. If a signal is received during that time that has no signal handler, the process ends instantly. So far so good.
But when a signal is received that has a signal handler, the signal handler is executed and the open() syscall is still blocking.
How can I make open() return when I catch the signal?
I tried to block the signal, that does not work because there is no sigmask argument for open() like there is for pselect(). Using O_NONBLOCK does not work either, because then open() will return with an error, whether there is a signal or not. Removing the signal handler is also no good because I want to be able to react to the signal.
My test code:
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static volatile bool end=0;
static void catchSignal(int signal)
{
(void)signal;
const char *s="Catched Signal\n";
write(STDERR_FILENO,s,strlen(s));
end=1;
}
static int openFile(void)
{
int fd=open("./in",O_RDONLY);
if(fd<0)
{
perror("can't open file");
exit(1);
}
return fd;
}
int main()
{
if(SIG_ERR==signal(SIGTERM,catchSignal))
{
perror("cant set up signal handler");
return -1;
}
int fd = openFile();
while(end==0)
{
puts("Still running");
usleep(300UL*1000);
}
puts("End now");
if(fd>0)
{
close(fd);
}
return 0;
}
The signal() function is problematic because of a history of implementations with different details. According to its Linux manual page:
The only portable use of signal() is to set a signal's disposition to SIG_DFL or SIG_IGN. The semantics when using signal() to establish a signal handler vary across systems (and POSIX.1 explicitly permits this variation); do not use it for this purpose.
(Emphasis in the original)
Instead of signal(), you should be using sigaction():
struct sigaction sa = { .sa_handler = catchSignal };
if (SIG_ERR == sigaction(SIGTERM, &sa, NULL))
Note that among the fields of a struct sigaction is sa_flags, a bitmask with which you can select among the various behaviors historically implemented by different versions of signal(). In particular, if you do not include the SA_RESTART flag, as the above indeed does not, then you should not see system calls automatically resume when interrupted by a signal (except for those few that are explicitly specified to do so).
When you strace your program, you see that signal() functions sets SA_RESTART flag for the signal:
rt_sigaction(SIGTERM, {sa_handler=0x562f2a8c3249, sa_mask=[TERM], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7fb504d2d210}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
meaning, that the open() syscall will be automatically restarted after handling the signal.
You can use sigaction() to have more fine-grained control over signal handling and not set the SA_RESTART:
struct sigaction sa;
memset (&sa, 0, sizeof (sa));
sa.sa_handler = catchSignal;
sa.sa_flags = 0;
sigemptyset (&sa.sa_mask);
if (sigaction (SIGTERM, &sa, NULL) == -1) {
perror("sigaction");
return -1;
}
you can use O_NONBLOCK in which case open() will return immediately, and you will block as soon as you fcntl(2) cancelling the O_NONBLOCK.
Read the man page, as probably you have some way to make open(2) return -1 and errno equal to EINTR. But the normal usage is what has been described, the call is reissued, so the signal handler doesn't make the calll to be interrupted (much code depends on this behaviour). I'm not sure about this, but I think only pause(2) and select(2) and friends are interrupted (and return) when a non-ignored signal is received.
Is worth noting that only the thread that is blocked in an interruptible call and receives the signal is awaken and the call interrupted, and the thread receiving the interrupt can be any of the ones you have started in your process.

can't get alarm() to work more than twice

static void AlarmHandler(int sig) ;
int i=0;
jmp_buf mark;
int main(int argc, char * argv[]){
setjmp(mark);
signal(SIGALRM, AlarmHandler);
alarm(2);
while(1);
return 0;
}
static void AlarmHandler(int sig) {
signal(SIGALRM, SIG_IGN);
printf("I am in AlarmHandler: %d \n",i);
i++;
longjmp(mark, 0);
}
When I run this code the program goes through the AlarmHandler only once and then it just stays trapped inside the while loop. Can someone explain why?
Your program might work as you expected on some POSIXy operating systems -- in fact, it does work as you expected on the computer I'm typing this on. However, it relies on a bunch of unspecified behavior relating to signals, and I think you've tripped over one of them: I think that on your computer, a signal is "blocked" — it can't be delivered again — while its handler is executing, and also, jumping out of the handler with longjmp does not unblock the signal. So you go around the loop once and then the second SIGALRM is never delivered because it's blocked. There are several other, related problems.
You can nail down all of the unspecified behavior and make the program reliable on all POSIXy operating systems, but you have to use different functions to set things up: sigsetjmp and sigaction. You should also get rid of the busy-waiting by using sigsuspend instead. A corrected program would look something like this:
#define _XOPEN_SOURCE 700
#include <signal.h>
#include <setjmp.h>
#include <stdio.h>
#include <unistd.h>
static jmp_buf mark;
static void
handle_SIGALRM(int sig)
{
static int signal_count;
signal_count++;
printf("SIGALRM #%u\n", signal_count);
siglongjmp(mark, signal_count);
}
int
main(void)
{
sigset_t mask, omask;
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
if (sigprocmask(SIG_BLOCK, &mask, &omask)) {
perror("sigprocmask");
return 1;
}
struct sigaction sa;
sigfillset(&sa.sa_mask);
sa.sa_flags = 0; // DO interrupt blocking system calls
sa.sa_handler = handle_SIGALRM;
if (sigaction(SIGALRM, &sa, 0)) {
perror("sigaction");
return 1;
}
if (sigsetjmp(mark, 1) >= 4)
return 0;
alarm(1);
sigsuspend(&omask);
perror("shouldn't ever get here");
return 1;
}
I should probably say a few words about signal safety: In this program, it is safe to call printf and siglongjmp from the signal handler, because I have arranged for the SIGALRM only to be deliverable while the main thread of execution is blocked on sigsuspend. (That's what the call to sigprocmask up top does.) If you had anything to do in your main thread of execution besides sleep waiting for the signal to arrive, you would have to be much more careful about what you did in the signal handler, and I would advocate for using pselect and/or the self-pipe trick instead of jumping out of the handler, if at all possible.

Why signal handling is malfunctioning?

I have a signal handling snippet but it is somehow malfunctioning on my Mac and virtual Linux box at koding.com but on my office Linux PC it is working..Can someone please tell me why..
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void my_isr(int n){
printf("Hello World");
signal(SIGINT, SIG_DFL);
}
int main(){
signal(SIGINT, my_isr);
printf("pid = %d\n", getpid());
while(1);
return 0;
}
When I am pressing Ctrl+C it is not printing Hello World on the first time but it is re-modifying the SIGINT signal action & hence it is exiting the program when I press Ctrl+C second time. Can someone explain me why?
You are not allowed to call every function in a signal handler.
Read signal(7). Only async signal safe functions can be called (directly or indirectly) from a signal handler, and printf is not such a function. If you really want to reliably "print" something from inside a signal handler (which I don't recommend), you can only use the low-level write(2) syscall (it is async signal safe).
So you've got undefined behavior. This explains why it is so bad.
The recommended way is to set a volatile sigatomic_t flag in your signal handler, and to test it outside of it (e.g. in your while loop...).
And you forgot to call fflush(3). You might be more lucky by ending your printf format string with \n since stdout is line-buffered!
Of course, changing your printf inside your signal handler is still UB, even with a \n, but very often it would appear to work.
Here is a conforming version of your program....
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
volatile sig_atomic_t got_signal;
void my_sigint_handler (int signum) {
if (signum == SIGINT) // this is always true!
got_signal = 1;
#define INTERRUPT_MESSAGE "Interrupted!\n"
write(STDOUT_FILENO, INTERRUPT_MESSAGE, strlen(INTERRUPT_MESSAGE));
};
int main(int argc, char**argv) {
struct sigaction act_int;
memset (&act_int, 0, sizeof(act_int));
act_int.sa_handler = my_sigint_handler;
if (sigaction(SIGINT, &act_int, NULL)) {
perror("sigaction"); exit(EXIT_FAILURE);
};
printf ("start %s pid %d\n", argv[0], (int)getpid());
while (!got_signal) {
};
printf ("ended %s after signal\n", argv[0]);
return 0;
}
A useful (and permissible) trick could be to write(2) a single byte -inside your signal handler- on a pipe(7) to self (you set up that pipe using pipe(2) early at program initialization), and in your event loop poll(2) the read end of that pipe.
printf is the culprit just use counter in handler and print outside handler its value it will work.
use sigaction instead of signal

Custom SIGINT signal handler - Program still terminates even after signal is caught

I am playing with the signal.h and unistd.h libraries, and I am having some issues. In the code below, when I send the SIGINT signal to my running program by calling CTRL-C, the signal is caught. However, when pressing CTRL-C again, the program terminates. As I understand it, the print statement "Received signal 2" should be printed every time I press CTRL-C.
Is my understanding of this signal incorrect, or is there a bug in my code?
Thanks for your input!
#include "handle_signals.h"
void sig_handler(int signum)
{
printf("\nReceived signal %d\n", signum);
}
int main()
{
signal(SIGINT, sig_handler);
while(1)
{
sleep(1);
}
return 0;
}
Terminal output:
xxx#ubuntu:~/Dropbox/xxx/handle_signals$ ./handle_signals
^C
Received signal 2
^C
xxx#ubuntu:~/Dropbox/xxx/handle_signals$
Edit: Here is the header I've included
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void sig_handler(int signum);
Thanks for your responses. Reading through them now!
Don't use signal, use sigaction:
The behavior of signal() varies across UNIX versions, and has also varied historically across different versions of Linux. Avoid its use: use sigaction(2) instead.
http://man7.org/linux/man-pages/man2/signal.2.html
In the original UNIX systems, when a handler that was established using signal() was invoked by the delivery of a signal, the disposition of the signal would be reset to SIG_DFL, and the system did not block delivery of further instances of the signal.
Linux implements the same semantics: the handler is reset when the signal is delivered.
The behaviour of signal upon receiving the first signal varies on different implementation. Typically, it requires reinstalling the handler after receiving the signal as handler is reset to its default action:
void sig_handler(int signum)
{
signal(SIGINT, sig_handler);
printf("\nReceived signal %d\n", signum);
}
which is one of the reasons you shouldn't use signal anymore and use sigaction. You can see a bare bone example of using sigaction here.

Make a signal switch the action of another signal

I am working in C language. I am trying to catch and process two different signals:
INT: when this signal is caught, action1 or action2 is triggered
QUIT: when this signal is caught, the INT signal action is switched (action1->action2 or action2->action1)
Default INT signal action is set to action1.
In my code,switchaction function is well triggered by QUIT signal, but has no effect on INT signal action :s
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
typedef void (*sighandler_t)(int);
sighandler_t prev_handler;
void action1(int n){
printf("First message\n");
}
void action2(int n){
printf("Second message\n");
}
void switchaction(int n){
printf("Switch action\n");
prev_handler=action2;
}
int main() {
prev_handler = action1;
printf("PID: %d\n", getpid());
prev_handler= signal(SIGINT,prev_handler);
signal(SIGQUIT,switchaction);
travail(); //This function never ends
}
Would you have any idea of what is wrong in my code ?
Thanks,
Yann
Your syscall
prev_handler= signal(SIGINT,prev_handler);
is setting the signal handler to the value of prev_handler variable at the moment you are executing the signal syscall. Changing (after) the value of prev_handler does not change the handling of SIGINT signal. In other words, signal (and most C calls) have a call by value semantics. If you call signal once, the kernel keep the same handler (till you call signal again with the same signal number, or till you call sigaction(2) etc...).
Read carefully (assuming you are on Linux) the signal(7) and signal(2) man pages.
I would instead define
volatile sig_atomic_t howhandle;
void switchaction(int n __attribute__((unused))) {
if (howhandle)
howhandle = 0;
else
howhandle = 1;
}
void handleint (int n) {
if (howhandle) action1(n); else action2(n);
}
and install just
signal(SIGINT, handleint);
signal(SIGQUIT, switchaction);
Also, notice that calling printf inside a handler is incorrect (because printf is not an async-signal-safe function, but you call it in action1, called by handleint...). Read again signal(7)
You should have some other volatile sig_atomic_t variables and test (and clear them) at appropriate places inside your travail working function, but set them only in your signal handlers. Setting a volatile sig_atomic_t variable is pretty much the only thing you can do reliably inside a signal handler.
If you accept Linux specific solutions learn more about signalfd(2) (and use also poll(2)...). Read also Advanced Linux Programming.

Resources