EINTR and blocking recv call - c

I'm reading http://250bpm.com/blog:12 to understand how EINTR should/could be handled and I have trouble reconciling the second and third source code snippet with description.
Second listing:
volatile int stop = 0;
void handler (int)
{
stop = 1;
}
void event_loop (int sock)
{
signal (SIGINT, handler);
while (1) {
if (stop) {
printf ("do cleanup\n");
return;
}
char buf [1];
recv (sock, buf, 1, 0);
printf ("perform an action\n");
}
}
Third listing:
volatile int stop = 0;
void handler (int)
{
stop = 1;
}
void event_loop (int sock)
{
signal (SIGINT, handler);
while (1) {
if (stop) {
printf ("do cleanup\n");
return;
}
char buf [1];
int rc = recv (sock, buf, 1, 0);
if (rc == -1 && errno == EINTR)
continue;
printf ("perform an action\n");
}
}
Specifically:
POSIX specification defines that when signal (such as Ctrl+C) is caught, recv returns EINTR error. That allows the event loop to wrap over and check the 'stop' variable:
But the explanation given for supposed blocking in 2nd listing is that:
The problem is that recv is a blocking function. If Ctrl+C is pressed
while the event loop is blocked in recv, you'll get a kind of
deadlock: Signal handler is executed as expected, it sets 'stop' to 1,
but then the execution blocks. The event loop is stuck in recv and has
no opportunity to check whether 'stop' was set to 1.
Well, signal handler is defined in both cases and so the SIGINT is caught, therefore it seems like recv should unblock in both cases, no?

Related

Program won't end after catching SIGINT before pressing ENTER?

Why does my program not end until I press ENTER in terminal after pressing Ctrl+C?
Here is my code:
static volatile sig_atomic_t keepRunning = 1;
void intHandler(int sig)
{
keepRunning = 0;
}
int main(int argc, char *argv[])
{
signal(SIGINT, intHandler);
int ch;
while((ch = fgetc(stdin)) && keepRunning)
{
...
}
exit(EXIT_SUCCESS);
}
I have setup my while loop to read chars from stdin and to run until the SIGINT is caught. After that the keepRunning will be set to 0 and loop should end and terminate the program. However when I hit Ctrl+C my program doesn't accept any input anymore but it doesn't let me type any command in terminal until I press ENTER key. Why is that?
It is because fgetc() is blocking the execution, and the way you chose to handle SIGINT - fgetc() will NOT be interrupted with EINTR (see #AnttiHaapala's answer for further explanation). So only after you press enter, which releases fgetc(), keepRunning is being evaluated.
The terminal is also buffered, so only when you press enter it will send the chars to the FILE * buffer and will read by fgetc() one by one. This is why it exists only after pressing enter, and not other keys.
One of several options to "solve" it is to use nonblocking stdin, signalfd and epoll (if you use linux):
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/epoll.h>
#include <sys/signalfd.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <error.h>
int main(int argc, char *argv[])
{
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
/* Block signals so that they aren't handled
according to their default dispositions */
sigprocmask(SIG_BLOCK, &mask, NULL); // need check
// let's treat signal as fd, so we could add to epoll
int sfd = signalfd(-1, &mask, 0); // need check
int epfd = epoll_create(1); // need check
// add signal to epoll
struct epoll_event ev = { .events = EPOLLIN, .data.fd = sfd };
epoll_ctl(epfd, EPOLL_CTL_ADD, sfd, &ev); // need check
// Make STDIN non-blocking
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
// add STDIN to epoll
ev.data.fd = STDIN_FILENO;
epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev); // need check
char ch;
int keepRunning = 1; // no need to synchronize anymore
while(keepRunning) {
epoll_wait(epfd, &ev, 1, -1); // need check, must be always 1
if (ev.data.fd == sfd) {
printf("signal caught\n");
keepRunning = 0;
} else {
ssize_t r;
while(r = read(STDIN_FILENO, &ch, 1) > 0) {
printf("%c", ch);
}
if (r == 0 && errno == 0) {
/* non-blocking non-eof will return 0 AND EAGAIN errno */
printf("EOF reached\n");
keepRunning = 0;
} else if (errno != EAGAIN) {
perror("read");
keepRunning = 0;
}
}
}
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) & ~O_NONBLOCK);
exit(EXIT_SUCCESS);
}
Also note that I'm not using fgetc(). Because of buffering nature of FILE *, it will not work well with nonblocking IO.
The program above is intended for education purposes only and not for "production" use. There are several issue that need attention, for example:
All the libc / system calls need to tested for errors.
If output is slower than input (printf() may easily be slower), it may cause starvation and the signal will not get caught (the inner loop will exit only after input is over/slower).
Performance / reduction of system calls:
read() can fill much larger buffer.
epoll_wait can return multiple events instead of 1.
Usually system calls return with errno == EINTR if a signal was delivered when they're blocking, which would cause fgetc to return early with an error condition as soon as Control-C was hit. The problem is that the signal set by signal will be set to auto restarting mode, i.e. the underlying read system call would be restarted as soon as the signal handler completed.
The correct fix would be to remove the automatic restart but it does make it slightly trickier to use correctly. Here we see if the return value is EOF from fgetc and then if it is caused by EINTR and restart the loop if the boolean was not true.
struct sigaction action = {
.sa_flags = 0,
.sa_handler = intHandler
};
sigaction(SIGINT, &action, NULL);
int ch;
while (1) {
ch = fgetc(stdin);
if (ch == EOF) {
if (errno == EINTR) {
if (keepRunning) {
continue;
}
break;
}
break;
}
}

Killing child with SIGTERM

I have 2 programs: 1) Father 2) Child.
When Father receives SIGINT (CTRL-C) signal his handler sends a SIGTERM to his child. The problem is that often (not always, don't know why) it shows this error in loop after SIGINT:
Invalid Argument
Goal of the father is to create a child and then just being alive to be ready to handle SIGINT.
Father
#include "library.h"
static void handler();
int main(int argc, char* argv[]){
int value, que_id;
char str_que_id[10], **child_arg;
pid_t child_pid;
sigaction int_sa;
//Create message queue
do{
que_id = msgget(IPC_PRIVATE, ALL_PERM | IPC_CREAT);
}while(que_id == -1);
snprintf(str_que_id, sizeof(str_que_id), "%d", que_id);
//Set arguments for child
child_arg = malloc(sizeof(char*) * 3);
child[0] = "child";
child[1] = str_que_id;
child[2] = NULL;
//Set handler for SIGINT
int_sa.sa_handler = &handler;
int_sa.sa_flags = SA_RESTART;
sigemptyset(&int_sa.sa_mask);
sigaddset(&int_sa.sa_mask, SIGALRM);
sigaction(SIGINT, &int_sa, NULL);
//Fork new child
if(value = fork() == 0){
child_pid = getpid();
do{
errno = 0;
execve("./child", child_arg, NULL);
}while(errno);
}
//Keep alive father
while(1);
return 0;
}
static void handler(){
if(kill(child_pid, SIGTERM) != -1)
waitpid(child_pid, NULL, WNOHANG);
while(msgctl(que_id, IPC_RMID, NULL) == -1);
free(child_arg);
exit(getpid());
}
Goal of the child (only for now in my project) is just to wait a new message incoming from the message queue. Since there won't be any message, it will always be blocked.
Child
#include "library.h"
typedef struct _Msgbuf {
long mtype;
char[10] message;
} Msgbuf;
int main(int argc, char * argv[]){
int que_id;
//Recovery of message queue id
que_id = atoi(argv[1]);
//Set handler for SIGTERM
signal(SIGTERM, handler);
//Dynamic allocation of message
received = calloc(1, sizeof(Msgbuf));
while(1){
do{
errno = 0;
//This will block child because there won't be any message incoming
msgrcv(que_id, received, sizeof(Msgbuf) - sizeof(long), getpid(), 0);
if(errno)
perror(NULL);
}while(errno && errno != EINTR);
}
}
static void handler(){
free(received);
exit(getpid());
}
I know from the man pages on msgrcv():
The calling process catches a signal. In this case the system call fails with errno set to EINTR. (msgrcv() is never automatically restarted after being interrupted by a signal handler, regardless of the setting of the SA_RESTART flag when establishing a signal handler.)
So why does it go to loop printing that error? It should exit in the handler instead it seems that after the handler comes back and (since the free(received) ) it doesn't find the buffer of the message setting errno to EINVAL .
(Almost) always errno only carries a sane value if and only if a function call failed.
This is the case for msgrcv().
From msgrcv()'s documentation:
RETURN VALUE
Upon successful completion, msgrcv() shall return a value equal to the number of bytes actually placed into the buffer mtext. Otherwise, no message shall be received, msgrcv() shall return -1, and errno shall be set to indicate the error.
So only use errno if msgrcv() returned -1, else errno's value is undefined and it might very well contain garbage or not ...
The code below does not make sense ...
msgrcv(que_id, received, sizeof(Msgbuf) - sizeof(long), getpid(), 0);
if(errno)
perror(NULL);
} while(errno && errno != EINTR);
... and should look like:
if (-1 == msgrcv(que_id, received, sizeof(Msgbuf) - sizeof(long), getpid(), 0))
{
/* Only here errno had a well defined value. */
perror("msgrcv() failed"); /* perror() translates errno into a human readable text prefixed by its argument and logs it to the stderr. */
}
else
{
errno = 0;
}
} while (errno && errno != EINTR);
This BTW
do{
errno = 0;
execve("./child", child_arg, NULL);
}while(errno);
only works as the members of the exec*() family of functions only return on error. So when the while's condition is tested then execve() had failed, though errno had been set. Here also the initial errnr = 0; setting is useless.
There are a number of problems with your program. It invokes undefined behaviour by calling exit, free, and msgctl from within the signal handlers. The table in the Signal Actions section of The Open Group Base Specifications lists the functions that are safe to call from within a signal handler. In most cases, you simply want to toggle a "running" flag from within the handler and have your main loop run until it is told to exit. Something like the following simple example:
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/* this will be set when the signal is received */
static sig_atomic_t running = 1;
void
sig_handler(int signo, siginfo_t *si, void *context)
{
running = 0;
}
int
main(int argc, char *argv[])
{
int rc;
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = &sig_handler;
rc = sigaction(SIGINT, &sa, NULL);
if (rc < 0) {
perror("sigaction");
exit(EXIT_FAILURE);
}
printf("Waiting for SIGINT\n");
while (running) {
printf("... sleeping for 10 seconds\n");
sleep(10);
}
printf("Signal received\n");
return 0;
}
I put together a more complex session on repl.it as well.
The other problem is that you assume that errno retains a zero value across function calls. This is likely the case but the only thing that you should assume about errno is that it will be assigned a value when a library function returns a failure code -- e.g., read returns -1 and sets errno to something that indicates the error. The conventional way to call a C runtime library function is to check the return value and consult errno when appropriate:
int bytes_read;
unsigned char buf[128];
bytes_read = read(some_fd, &buf[0], sizeof(buf));
if (bytes_read < 0) {
printf("read failed: %s (%d)\n", strerror(errno), errno);
}
Your application is probably looping because the parent is misbehaving and not waiting on the child or something similar (see above about undefined behavior). If the message queue is removed before the child exits, then the msgrcv call is going to fail and set errno to EINVAL. You should check if msgrcv is failing before you check errno. The child should also be terminating the loop when it encounters a msgrcv failure with errno equal to EINVAL since that is a terminal condition -- the anonymous message queue can never be recreated after it ceases to exist.

signal handler to terminate the main program and all forks when arrives a double SIGINT

I really didn't get how signal handlers work especially with forks. So i need to do this exercise but i couldn't get it work properly.
My main program makes 5 forks, each fork prints simply 10 messages with its pid. So the purpose of the program, when i send a SIGINT signal via keyboard(Ctrl-c) it should print, "a single SIGINT arrived", if two SIGINT arrives between one second, it should print "double SIGINT arrived" and should terminate the whole program. So when i launch my program, it handles first two SIGINT(that i send the second more than 1 second after the first one) but then it doesn't handle single SIGINT and neither double SIGINT.
So i'm very confused about signals. Forks continue to stamp messages. I load same handler both to main and to forks but what should i do to terminate all forks when arrives double SIGINT? Should i call killl or some other function in handler to terminate them?
the main function
/* libraries... */
volatile sig_atomic_t double_sigint = 0;
int64_t time_diff = 0;
int main()
{
int i;
int pid;
sigset_t set;
struct sigaction sa;
/* mask all signals */
/*H*/ if(sigfillset(&set) == -1 )
/*A*/ {perror("sigfillset"); exit(errno);}
/*N*/
/*D*/ if(sigprocmask(SIG_SETMASK,&set,NULL) == -1)
/*L*/ {perror("sigfillset"); exit(errno);}
/*E*/
/*R*/ memset(&sa,0,sizeof(sa));
/*B*/
/*L*/ sa.sa_handler = handler;
/*O*/
/*C*/ if(sigaction(SIGINT, &sa, NULL) == -1)
/*K*/ {perror("sigaction"); exit(errno);}
/**/
/**/ /* unmask all signals */
/**/ if( sigemptyset(&set) == -1 )
/**/ {perror("sigepmtyset"); exit(errno);}
/**/
/**/ if(sigprocmask(SIG_SETMASK,&set,NULL) == -1 )
/**/ {perror("sigprocmask"); exit(errno);}
for(i=0;i<5;++i)
{
if((pid = fork()) == -1)
{ perror("rec:fork"); exit(errno); }
if(pid == 0)/* figlio */
{
/* SAME HANDLER BLOCK IS HERE */
foo(i);
return;
}
sleep(1);
}
return 0;
}
foo function
void foo(int i)
{
int k;
for(k=0; k<10; ++k)
{
printf("%d. fork %d. print\n", i, k);
sleep(1);
}
}
signal handler
void handler (int signum) {
struct timespec sig1;
struct timespec sig2;
if(double_sigint == 0)
{
if(clock_gettime(CLOCK_REALTIME, &sig1))
{ perror("failed to get sig1 time"); exit(errno); }
write(1,"Received single SIGINT\n",18);
double_sigint = 1;
}
else if(double_sigint == 1)
{
if(clock_gettime(CLOCK_REALTIME, &sig2))
{ perror("failed to get sig2 time"); exit(errno); }
time_diff = (sig2.tv_sec - sig1.tv_sec) + (sig2.tv_nsec - sig1.tv_nsec)/1000000000;
if(time_diff < 1)
{
double_sigint = 2;
write(1,"Received double SIGINT\n",18);
_exit(EXIT_FAILURE);
}
else
{
sig1.tv_sec = sig2.tv_sec;
sig1.tv_nsec = sig2.tv_nsec;
write(1,"Received single SIGINT\n",18);
}
}
}
When you receive a double-SIGINT, you only kill the parent process, with the line _exit(EXIT_FAILURE);. The forks you have created before are not killed and keep running, their parent now being the init process.
If you want all the children to terminate, you have to kill them manually. Maybe this post would be helpful : How to make child process die after parent exits
Edit: That was not the problem since Ctrl+C sends a SIGINT to all the children (see comments).
What worked for me was :
As said in William Pursell's comment, make sig1 and sig2 global variables.
Make the parent process always run (just added a while (1); before the return statement), because some signals were not taken into account once the parent process was terminated.
In the handler, in the else clause (double_sigint == 1) you are comparing sig2 and sig1, but sig1 is uninitialized. The value that you gave it the first time the handler was called went away when that handler returned. You could simply give those variables file scope.
By using the uninitialized value of the local variable, you are getting undefined behavior. If the signal handler is called and the signal handling stack happens to be in the same state it was on the previous call, then things may work fine. This can happen if you send the signal twice with no intervening signals, for example. Since sleep is likely implemented with a signal, it is quite likely that the stack has been modified since the previous call and sig1 is not what you expect. However, speculation about undefined behavior is somewhat pointless.

Different pselect() behaviour on OSX vs Linux?

I am trying to implement a basic event loop with pselect, so I have blocked some signals, saved the signal mask and used it with pselect so that the signals will only be delivered during that call.
If a signal is sent outside of the pselect call, it is blocked until pselect as it should, however it does not interrupt the pselect call. If a signal is sent while pselect is blocking, it will be handled AND pselect will be interrupted. This behaviour is only present in OSX, in linux it seems to function correctly.
Here is a code example:
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
int shouldQuit = 0;
void signalHandler(int signal)
{
printf("Handled signal %d\n", signal);
shouldQuit = 1;
}
int main(int argc, char** argv)
{
sigset_t originalSignals;
sigset_t blockedSignals;
sigemptyset(&blockedSignals);
sigaddset(&blockedSignals, SIGINT);
if(sigprocmask(SIG_BLOCK, &blockedSignals, &originalSignals) != 0)
{
perror("Failed to block signals");
return -1;
}
struct sigaction signalAction;
memset(&signalAction, 0, sizeof(struct sigaction));
signalAction.sa_mask = blockedSignals;
signalAction.sa_handler = signalHandler;
if(sigaction(SIGINT, &signalAction, NULL) == -1)
{
perror("Could not set signal handler");
return -1;
}
while(!shouldQuit)
{
fd_set set;
FD_ZERO(&set);
FD_SET(STDIN_FILENO, &set);
printf("Starting pselect\n");
int result = pselect(STDIN_FILENO + 1, &set, NULL, NULL, NULL, &originalSignals);
printf("Done pselect\n");
if(result == -1)
{
if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
{
perror("pselect failed");
}
}
else
{
printf("Start Sleeping\n");
sleep(5);
printf("Done Sleeping\n");
}
}
return 0;
}
The program waits until you input something on stdin, then sleeps for 5 seconds. To create the problem, "a" is typed to create data on stdin. Then, while the program is sleeping, an INT signal is sent with Crtl-C.
On Linux:
Starting pselect
a
Done pselect
Start Sleeping
^CDone Sleeping
Starting pselect
Handled signal 2
Done pselect
On OSX:
Starting pselect
a
Done pselect
Start Sleeping
^CDone Sleeping
Starting pselect
Handled signal 2
^CHandled signal 2
Done pselect
Confirmed that it acts that way on OSX, and if you look at the source for pselect (http://www.opensource.apple.com/source/Libc/Libc-320.1.3/gen/FreeBSD/pselect.c), you'll see why.
After sigprocmask() restores the signal mask, the kernel delivers the signal to the process, and your handler gets invoked. The problem here is, that the signal can be delivered before select() gets invoked, so select() won't return with an error.
There's some more discussion about the issue at http://lwn.net/Articles/176911/ - linux used to use a similar userspace implementation that had the same problem.
If you want to make that pattern safe on all platforms, you'll have to either use something like libev or libevent and let them handle the messiness, or use sigprocmask() and select() yourself.
e.g.
sigset_t omask;
if (sigprocmask(SIG_SETMASK, &originalSignals, &omask) < 0) {
perror("sigprocmask");
break;
}
/* Must re-check the flag here with signals re-enabled */
if (shouldQuit)
break;
printf("Starting select\n");
int result = select(STDIN_FILENO + 1, &set, NULL, NULL, NULL);
int save_errno = errno;
if (sigprocmask(SIG_SETMASK, &omask, NULL) < 0) {
perror("sigprocmask");
break;
}
/* Recheck again after the signal is blocked */
if (shouldQuit)
break;
printf("Done pselect\n");
if(result == -1)
{
errno = save_errno;
if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
{
perror("pselect failed");
}
}
There are a couple of other things you should do with your code:
declare your 'shouldQuit' variable as volatile sig_atomic_t
volatile sig_atomic_t shouldQuit = 0;
always save errno before calling any other function (such as printf()), since that function may cause errno to be overwritten with another value. Thats why the code above aves errno immediately after the select() call.
Really, I strongly recommend using an existing event loop handling library like libev or libevent - I do, even though I can write my own, because it is so easy to get wrong.

sigtimedwait and detecting signals

I'm supposed to implement a signal handler which stops all the threads in the program the first time a certain signal is called, and resume them if they are already stopped. I implemented a demon thread running in the background using the following code:
void *handle_sig(void *arg)
{
sigset_t set;
//set set...
struct timespec to;
to.tv_sec = 1;
to.tv_nsec = 0;
while (_keepListening) {
int ret = sigtimedwait(&set, NULL, &to);
if (ret < 0)
if (errno == EAGAIN) {
continue; /* no signal sent*/
} else {
fprintf(stderr, "Failed...\n");
exit(1);
}
if (_state == PAUSE_STATE) { /* was blocked*/
//do something
} else {
` //do something else
}
}
return NULL;
}
The problem is that if a signal is sent and detected, and then another is sent before the while loop is entered again - the second signal is ignored, which can leave the program paused forever. is there a way of detecting if a signal was sent since the last call to sigtimedwait?
Thank you
You might think about making your processing asynchronous.
For example by starting a thread for "doing something" or "doing something else".

Resources