pclose() returns SIGPIPE intermittently - linux

When the following C program is executed, and SIGUSR1 is sent to the running process repeatedly, the pclose() call will sometimes return 13. 13 corresponds to SIGPIPE on my system.
Why does this happen?
I am using while true; do kill -SIGUSR1 <process-id>; done to send SIGUSR1 to the program. The program is executed on Ubuntu 14.04.
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
void handler(int i) {}
void* task(void*)
{
FILE *s;
char b [BUFSIZ];
while (1) {
if ((s = popen("echo hello", "r")) == NULL) {
printf("popen() failed\n");
}
while (fgets(b, BUFSIZ, s) != NULL) ;
if (int r = pclose(s)) {
printf("pclose() failed (%d)\n", r);
}
}
return 0;
}
int main(int argc, char **argv)
{
struct sigaction action;
action.sa_handler = handler;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
sigaction(SIGUSR1, &action, NULL);
pthread_t tid;
pthread_create(&tid, 0, task, NULL);
pthread_join(tid, NULL);
}

This happens when fgets gets interrupted by the signal. The program doesn't read the pipe to the end and closes it. The other program then SIGPIPEs.
The correct pipe reading operation is:
do {
while (fgets(b, BUFSIZ, s) != NULL) ;
} while (errno == EINTR);

Related

robust_list not calling FUTEX_WAKE

The Linux robust_list mechanism is a tool used by robust mutexes to support automatic unlocking in the event that the lock owner fails to unlock before terminating, maybe due to unexpected death. According to man set_robust_list:
The purpose of the robust futex list is to ensure that if a thread accidentally fails to unlock a futex before terminating or calling execve(2), another thread that is waiting on that futex is notified that the former owner of the futex has died. This notification consists of two pieces: the FUTEX_OWNER_DIED bit is set in the futex word, and the kernel performs a futex(2) FUTEX_WAKE operation on one of the threads waiting on the futex.
This is not the behavior I'm seeing.
I'm seeing the futex replaced with FUTEX_OWNER_DIED, not ored with.
And I'm not getting the FUTEX_WAKE call.
#include <chrono>
#include <thread>
#include <linux/futex.h>
#include <stdint.h>
#include <stdio.h>
#include <syscall.h>
#include <unistd.h>
using ftx_t = uint32_t;
struct mtx_t {
mtx_t* next;
mtx_t* prev;
ftx_t ftx;
};
thread_local robust_list_head robust_head;
void robust_init() {
robust_head.list.next = &robust_head.list;
robust_head.futex_offset = offsetof(mtx_t, ftx);
robust_head.list_op_pending = NULL;
syscall(SYS_set_robust_list, &robust_head.list, sizeof(robust_head));
}
void robust_op_start(mtx_t* mtx) {
robust_head.list_op_pending = (robust_list*)mtx;
__sync_synchronize();
}
void robust_op_end() {
__sync_synchronize();
robust_head.list_op_pending = NULL;
}
void robust_op_add(mtx_t* mtx) {
mtx_t* old_first = (mtx_t*)robust_head.list.next;
mtx->prev = (mtx_t*)&robust_head;
mtx->next = old_first;
__sync_synchronize();
robust_head.list.next = (robust_list*)mtx;
if (old_first != (mtx_t*)&robust_head) {
old_first->prev = mtx;
}
}
int futex(ftx_t* uaddr,
int futex_op,
int val,
uintptr_t timeout_or_val2,
ftx_t* uaddr2,
int val3) {
return syscall(SYS_futex, uaddr, futex_op, val, timeout_or_val2, uaddr2, val3);
}
int ftx_wait(ftx_t* ftx, int confirm_val) {
return futex(ftx, FUTEX_WAIT, confirm_val, 0, NULL, 0);
}
int main() {
mtx_t mtx = {0};
std::thread t0{[&]() {
fprintf(stderr, "t0 start\n");
ftx_wait(&mtx.ftx, 0);
fprintf(stderr, "t0 done\n");
}};
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::thread t1{[&]() {
fprintf(stderr, "t1 start\n");
robust_init();
robust_op_start(&mtx);
__sync_bool_compare_and_swap(&mtx.ftx, 0, syscall(SYS_gettid));
robust_op_add(&mtx);
robust_op_end();
fprintf(stderr, "t1 ftx: %x\n", mtx.ftx);
fprintf(stderr, "t1 done\n");
}};
t1.join();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
fprintf(stderr, "ftx: %x\n", mtx.ftx);
t0.join();
}
Running
g++ -o ./example ~/example.cpp -lpthread && ./example
prints something like:
t0 start
t1 start
t1 ftx: 12ea65
t1 done
ftx: 40000000
and hangs.
I would expect the final value of the futex to be 4012ea65 and for thread 0 to unblock after thread 1 completes.

Cygwin: interrupting blocking read

I've written the program which spawns a thread that reads in a loop from stdin in a blocking fashion. I want to make the thread return from blocked read immediately. I've registered my signal handler (with sigaction and without SA_RESTART flag) in the reading thread, send it a signal and expect read to exit with EINTR error. But it doesn't happen. Is it issue or limitation of Cygwin or am I doing something wrong?
Here is the code:
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
pthread_t thread;
volatile int run = 0;
void root_handler(int signum)
{
printf("%s ENTER (thread is %x)\n", __func__, pthread_self());
run = 0;
}
void* thr_func(void*arg)
{ int res;
char buffer[256];
printf("%s ENTER (thread is %x)\n", __func__, pthread_self());
struct sigaction act;
memset (&act, 0, sizeof(act));
act.sa_sigaction = &root_handler;
//act.sa_flags = SA_RESTART;
if (sigaction(SIGUSR1, &act, NULL) < 0) {
perror ("sigaction error");
return 1;
}
while(run)
{
res = read(0,buffer, sizeof(buffer));
if(res == -1)
{
if(errno == EINTR)
{
puts("read was interrupted by signal");
}
}
else
{
printf("got: %s", buffer);
}
}
printf("%s LEAVE (thread is %x)\n", __func__, pthread_self());
}
int main() {
run = 1;
printf("root thread: %x\n", pthread_self());
pthread_create(&thread, NULL, &thr_func, NULL);
printf("thread %x started\n", thread);
sleep(4);
pthread_kill(thread, SIGUSR1 );
//raise(SIGUSR1);
pthread_join(thread, NULL);
return 0;
}
I'm using Cygwin (1.7.32(0.274/5/3)).
I've just tried to do the same on Ubuntu and it works (I needed to include signal.h, though, even though in Cygwin it compiled as it is). It seems to be peculiarity of Cygwin's implementation.

Can not get proper response from select() using writefds

Parent receives SIGPIPE sending chars to aborted child process through FIFO pipe.
I am trying to avoid this, using select() function. In the attached sample code,
select() retruns OK even after the child at the other end of pipe having been terminated.
Tested in
RedHat EL5 (Linux 2.6.18-194.32.1.el5)
GNU C Library stable release version 2.5
Any help appreciated. Thnak you.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <unistd.h>
static void sigpipe_fct();
main()
{
struct stat st;
int i, fd_out, fd_in, child;
char buf[1024];
#define p_out "/tmp/pout"
signal(SIGPIPE, sigpipe_fct);
if (stat(p_out, &st) != 0) {
mknod(p_out, S_IFIFO, 0);
chmod(p_out, 0666);
}
/* start receiving process */
if ((child = fork()) == 0) {
if ((fd_in = open(p_out, O_RDONLY)) < 0) {
perror(p_out);
exit(1);
}
while(1) {
i = read(fd_in, buf, sizeof(buf));
fprintf(stderr, "child %d read %.*s\n", getpid(), i, buf);
lseek(fd_in, 0, 0);
}
}
else {
fprintf(stderr,
"reading from %s - exec \"kill -9 %d\" to test\n", p_out, child);
if ((fd_out = open(p_out, O_WRONLY + O_NDELAY)) < 0) { /* output */
perror(p_out);
exit(1);
}
while(1) {
if (SelectChkWrite(fd_out) == fd_out) {
fprintf(stderr, "SelectChkWrite() success write abc\n");
write(fd_out, "abc", 3);
}
else
fprintf(stderr, "SelectChkWrite() failed\n");
sleep(3);
}
}
}
static void sigpipe_fct()
{
fprintf(stderr, "SIGPIPE received\n");
exit(-1);
}
SelectChkWrite(ch)
int ch;
{
#include <sys/select.h>
fd_set writefds;
int i;
FD_ZERO(&writefds);
FD_SET (ch, &writefds);
i = select(ch + 1, NULL, &writefds, NULL, NULL);
if (i == -1)
return(-1);
else if (FD_ISSET(ch, &writefds))
return(ch);
else
return(-1);
}
From the Linux select(3) man page:
A descriptor shall be considered ready for writing when a call to an
output function with O_NONBLOCK clear would not block, whether or not
the function would transfer data successfully.
When the pipe is closed, it won't block, so it is considered "ready" by select.
BTW, having #include <sys/select.h> inside your SelectChkWrite() function is extremely bad form.
Although select() and poll() are both in the POSIX standard, select() is much older and more limited than poll(). In general, I recommend people use poll() by default and only use select() if they have a good reason. (See here for one example.)

SIGUSR1 not received

This is my first Program....ctrlcsignal.c
enter code here
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void signal_handler(int sigNo)
{
//if Ctrl+c signal
if(sigNo==SIGINT){
printf("value of SIGINT:-%d\t",SIGINT);
printf("received SIGINT\n");
}
// if some other signal , but this part wont get executed
// as the signal_handler function is registered with SIGINT only
else
{
printf("Some other signal found");
printf("value of other signal:-%d",sigNo);
}
}
int main(void)
{
//registering the signal handler function with a signal
kill(19574,SIGUSR1);
if(signal(SIGINT,signal_handler)==SIG_ERR)
{
printf("\n can't catch SIGINT\n");
}
while(1) //infinite loop
sleep(1); // 1s ,so that the CPU is not busy
return 0;
}
and this my second program....userdefinedsignals.c
enter code here
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void signal_handler(int sigNo)
{
printf("function entered...");
// check for userdefined Signal SIGUSR1
if (sigNo == SIGUSR1)
{
printf("received SIGUSR1 with value :- %d",SIGUSR1);
}
//checking for KILL Signal
else if (sigNo == SIGKILL)
{
printf("received SIGKILL with value :- %d",SIGKILL);
}
//checking for STOP Signal
else if (sigNo == SIGSTOP)
{
printf("received SIGSTOP with value :- %d",SIGSTOP);
}
// if some other signal , but this part wont get executed
// as the signal_handler function is registered with SIGINT only
else
{
printf("Some other signal found");
printf("value of other signal:-%d",sigNo);
}
}
int main(void)
{
int pid_t;
printf("process id is %d",getpid());
//registering the signal handler function with a signal
if(signal(SIGUSR1,signal_handler) == SIG_ERR)
{
printf("\n can't catch SIGSIGUSR1\n");
}
if(signal(SIGKILL,signal_handler)==SIG_ERR)
{
printf("\n can't catch SIGKILL\n");
}
if(signal(SIGSTOP,signal_handler)==SIG_ERR)
{
printf("\n can't catch SIGSTOP\n");
}
while(1) //infinite loop
sleep(1); // 1s ,so that the CPU is not busy
return 0;
}
I get the pid of the second process ... suppose xxxx
then i use the following command...
enter code here
kill -USR1 xxxx
but it shows nothing ....
also then i tried by calling the following function int the first program...but no use..
enter code herekill(xxxx,SIGUSR1);
HELP ME..!!!!
Works here.
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdarg.h> /* vsnprintf() */
#include <signal.h> /* signal */
void myprintf(FILE *fp, char *fmt, ...)
{
char buff[512];
int rc,fd;
va_list argh;
va_start (argh, fmt);
rc = vsnprintf(buff, sizeof buff, fmt, argh);
if (rc < 0 || rc >= sizeof buff) {
rc = sprintf(buff, "Argh!: %d:\n", rc);
}
if (!fp) fp = stderr;
fd = fileno(fp);
if (fd < 0) return;
if (rc > 0) write(fd, buff, rc);
return;
}
void signal_handler(int sigNo)
{
switch (sigNo ) {
case SIGUSR1:
myprintf(NULL, "received SIGUSR1 with value :- %d\n", SIGUSR1);
break;
case SIGKILL:
myprintf(NULL, "received SIGKILL with value :- %d\n", SIGKILL);
break;
case SIGSTOP:
myprintf(NULL, "received SIGSTOP with value :- %d\n", SIGSTOP);
break;
default:
myprintf(NULL, "Some other signal occured: %d\n", sigNo);
break;
}
return;
}
int main(void)
{
pid_t mypid;
mypid = getpid();
printf("process id is %d\n", (int) mypid);
if(signal(SIGUSR1,signal_handler) == SIG_ERR)
{ printf("\n can't catch SIGSIGUSR1\n"); }
if(signal(SIGKILL,signal_handler)==SIG_ERR)
{ printf("\n can't catch SIGKILL\n"); }
if(signal(SIGSTOP,signal_handler)==SIG_ERR)
{ printf("\n can't catch SIGSTOP\n"); }
if(signal(SIGCONT,signal_handler)==SIG_ERR)
{ printf("\n can't catch SIGCONT\n"); }
while(1) {
sleep(1);
}
return 0;
}
You're catching the signal all right, but not seeing the message because you don't terminate lines properly, and the standard output stream on your system is line buffered (assuming your program runs in a terminal).
Standard C defines three levels of buffering for output streams:
unbuffered, where output is transmitted immediately
line buffered, where output is transmitted when a newline character is encountered
fully buffered, where output is transmitted when an internal buffer fills
(This is a simplification - see a C reference or the Standard for details).
Consider:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
printf("Hello");
pause();
}
This produces no output in a terminal. Fix it by terminating the line:
printf("Hello\n");
This will produce the expected output in a terminal.
If stdout is not connected to a terminal - for example, you redirect to a file - then the stream becomes fully buffered. This:
./a.out > foo
Ctrl-C
cat foo
produces no output, even with the newline character added. Here you need an explicit flush to transmit the output before the buffer is full.
#include <stdio.h>
#include <unistd.h>
int main(void)
{
printf("Hello\n");
fflush(stdout);
pause();
}
This produces output even when redirected to a file.

Logging a message from SIGTERM

What's the proper way to log a shutdown message when an application (a C++ daemon, in my case) receives a SIGTERM or SIGINT?
According to CERT and the signal(7) manpage, many functions (including, presumably, those used by most logging libraries) aren't safe to call from signal handlers.
Vlad Lazarenko wrote a great blog post earlier this year on this very topic. On Linux it boils down to creating a signal descriptor with signalfd(2) and use an event loop such as poll(2) or epoll_wait(2). Here is Vlad's example reading from the descriptor
#include <sys/signalfd.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int
main(int argc, char *argv[])
{
sigset_t mask;
int sfd;
struct signalfd_siginfo fdsi;
ssize_t s;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGQUIT);
/* Block signals so that they aren't handled
according to their default dispositions */
if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
handle_error("sigprocmask");
sfd = signalfd(-1, &mask, 0);
if (sfd == -1)
handle_error("signalfd");
for (;;) {
s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
if (s != sizeof(struct signalfd_siginfo))
handle_error("read");
if (fdsi.ssi_signo == SIGINT) {
printf("Got SIGINT\n");
} else if (fdsi.ssi_signo == SIGQUIT) {
printf("Got SIGQUIT\n");
exit(EXIT_SUCCESS);
} else {
printf("Read unexpected signal\n");
}
}
}
This example can easily be extended to integrate into an event loop.
Logging could be done not from handler, but after it:
int received_sigterm = 0;
void
sigterm_handler(int sig)
{
received_sigterm = 1;
}
void
loop(void)
{
for(;;) {
sleep(1);
if (received_sigterm)
log("finish\n");
}
}
int
main()
{
log("start\n");
signal(SIGTERM, sigterm_handler);
loop();
}
The concept is borrowed from openssh-6.1 sources.

Resources