LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 12-05-2014, 04:34 AM   #1
user@123
LQ Newbie
 
Registered: Mar 2014
Posts: 18

Rep: Reputation: Disabled
Unblock fgets when signal is received.


Hello All,

In following program i registered signal SIGINT. When executing this program if SIGINT is sent while fgets is waiting for input, i want to do something in signal handler so that fgets should be unblocked and further processing should happen.

#include <stdio.h>
#include <signal.h>

void SignalHandler(int Signum)
{
//
// Signal received.
//
}

int main(int argc, char const *argv[])
{
char szBuffer[50];
signal(SIGINT, SignalHandler);
fgets(szBuffer, sizeof(szBuffer), stdin);

//
// Do further processing.
//
return 0;
}
 
Old 12-05-2014, 04:45 AM   #2
mina86
Member
 
Registered: Aug 2008
Distribution: Debian
Posts: 517

Rep: Reputation: 229Reputation: 229Reputation: 229
You can do stuff in the signal handler. If you want your main function to continue executing, I'm afraid you need to use lower level read function (at which point you'll have to take care of buffering and finding line ends) which returns -1 with errno == EINTR when signal is returned.
 
Old 12-05-2014, 08:48 AM   #3
SoftSprocket
Member
 
Registered: Nov 2014
Posts: 399

Rep: Reputation: Disabled
It's ugly but you can do this:
Code:
#include <signal.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>

jmp_buf return_here;

void sigint_handler (int signum) {
        longjmp (return_here, 1);
}       

int main () {
        signal (SIGINT, sigint_handler);
        
        while (1) {
                if (setjmp (return_here)) {
                        printf ("Hello, sigint!\n");
                        signal (SIGINT, sigint_handler);
                }       
                
                char inp[40];
                fgets (inp, 40, stdin);
                printf ("%s\n", inp);
        }       
        
        return 0;
}
There are better ways such as using signalfd in Linux and polling on the file descriptors.
 
Old 12-05-2014, 10:22 AM   #4
mina86
Member
 
Registered: Aug 2008
Distribution: Debian
Posts: 517

Rep: Reputation: 229Reputation: 229Reputation: 229
If the above works, it's only by sheer luck. For one, there is a race condition between when signal handler is set up and when jmp_buf is initialized. Furthermore, this will accumulate stuff on your stack. And lastly, you leave the standard library in God knows hat state when you abruptly interrupt fgets. It's not that it's “ugly”, it's plane broken.
 
Old 12-05-2014, 11:11 AM   #5
SoftSprocket
Member
 
Registered: Nov 2014
Posts: 399

Rep: Reputation: Disabled
Quote:
Originally Posted by mina86 View Post
If the above works, it's only by sheer luck. For one, there is a race condition between when signal handler is set up and when jmp_buf is initialized. Furthermore, this will accumulate stuff on your stack. And lastly, you leave the standard library in God knows hat state when you abruptly interrupt fgets. It's not that it's “ugly”, it's plane broken.
The race condition condition is there, true, but that's easily fixed by setting the handler after setjmp.

The standard library affected? How? Longjmp can be safely used from a signal handler, fgets can be intermixed with other buffered io so there can't be an impact on other calls. The contents of the buffer will be lost but fgets will continue to function. Broken? Maybe but the hyperbole is a little over the top.
 
Old 12-05-2014, 01:14 PM   #6
mina86
Member
 
Registered: Aug 2008
Distribution: Debian
Posts: 517

Rep: Reputation: 229Reputation: 229Reputation: 229
Code:
#define _POSIX_C_SOURCE 1

#include <setjmp.h>
#include <signal.h>
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>


#define DIE_ON(cond, str) do {			\
		if ((cond)) {			\
			perror(str);		\
			return 1;		\
		}				\
	} while (0)

static void print(const char *str) {
	puts(str);
	fflush(stdout);
}


static jmp_buf return_here;

static void handler(int signum) {
	signum = signum;
	longjmp(return_here, 1);
}

static int child(FILE *fh) {
	char buf[1024];
	signal(SIGUSR1, handler);

	while (1) {
		if (setjmp(return_here)) {
			print("CHLD: SIG");
			signal(SIGUSR1, handler);
		}

		if (!fgets(buf, sizeof buf, fh)) {
			print("CHLD: EOF");
			return 0;
		}

		printf("CHLD: GOT: %s", buf);
		fflush(stdout);
	}
}


static int parent(int fd, pid_t pid) {
	print("PRNT: send \"foo\"");
	DIE_ON(write(fd, "foo", 3) != 3, "write");
	sleep(1);  /* Make sure data went through */

	print("PRNT: kill");
	DIE_ON(kill(pid, SIGUSR1) < 0, "kill");
	sleep(1); /* Make sure child had a chance to run */

	print("PRNT: send \"bar\\n\"");
	DIE_ON(write(fd, "bar\n", 4) != 4, "write");

	return 0;
}


int main(void) {
	int fds[2];
	pid_t pid;

	DIE_ON(pipe(fds) < 0, "pipe");

	pid = fork();
	DIE_ON(pid < 0, "fork");

	if (pid) {
		close(fds[0]);
		return parent(fds[1], pid);
	} else {
		close(fds[1]);
		return child(fdopen(fds[0], "r"));
	}
}
Code:
$ ./a 
PRNT: send "foo"
PRNT: kill
CHLD: SIG
PRNT: send "bar\n"
CHLD: GOT: bar
CHLD: EOF
Notice how child received “bar\n” while parent sent “foobar\n”.

So I still claim using longjmp is broken (but I was incorrect in claiming that stack will grow indefinitely).

Last edited by mina86; 12-05-2014 at 01:24 PM.
 
Old 12-05-2014, 01:25 PM   #7
SoftSprocket
Member
 
Registered: Nov 2014
Posts: 399

Rep: Reputation: Disabled
Quote:
Originally Posted by mina86 View Post
Notice how child received “bar\n” while parent sent “foobar\n”.

So I still claim using longjmp is broken (but I was incorrect in claiming that stack will grow indefinitely).
There are places where you can use it and places where you can't. In the simple case presented by the OP you can; in the case you present you can't.
 
Old 12-05-2014, 03:09 PM   #8
mina86
Member
 
Registered: Aug 2008
Distribution: Debian
Posts: 517

Rep: Reputation: 229Reputation: 229Reputation: 229
Quote:
Originally Posted by SoftSprocket View Post
There are places where you can use it and places where you can't.
You can say the same about gets.
Quote:
Originally Posted by SoftSprocket View Post
In the simple case presented by the OP you can; in the case you present you can't.
OP's case is reading lines. My example shows reading lines. They do not differ.

Update: An example witch breaks your code:
Code:
$ cat reader.c 
#include <signal.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>

jmp_buf return_here;

void sigint_handler (int signum) {
	signum = signum;
	longjmp (return_here, 1);
}

int main(void) {
	signal (SIGINT, sigint_handler);

	while (1) {
		if (setjmp (return_here)) {
			printf ("Hello, sigint!\n");
			signal (SIGINT, sigint_handler);
		}

		char inp[40];
		if (!fgets (inp, 40, stdin)) {
			return 0;
		}
		printf ("%s\n", inp);
	}
}
$ cat writer.c 
#include <stdio.h>
#include <unistd.h>

static const char *const strings[] = {
	"foo-", "bar-", "baz-", "qux\n", NULL
};

int main(void) {
	const char *const *str = strings;
	for (; *str; ++str) {
		sleep(1);
		fputs(*str, stdout);
		fflush(stdout);
	}
	return 0;
}
$ sh -x run.sh 
+ ./writer
+ sleep 2
+ ./reader
+ kill -INT 11674
+ wait
Hello, sigint!
baz-qux
Notice how reader only reads “baz-qux”.

Last edited by mina86; 12-05-2014 at 03:29 PM. Reason: Added example with SoftSprocket's reader code.
 
Old 12-05-2014, 03:32 PM   #9
SoftSprocket
Member
 
Registered: Nov 2014
Posts: 399

Rep: Reputation: Disabled
Quote:
Originally Posted by mina86 View Post
You can say the same about gets.

OP's case is reading lines. My example shows reading lines. They do not differ.
You can't say the same thing about gets. There is no safe way to use gets. Longjmp can be safely used and it can be safely used in signal handlers. You just need to be aware that the state of the data being read at the time of the interrupt is indeterminate.

So far you've made no argument to support your position.
 
Old 12-05-2014, 03:45 PM   #10
SoftSprocket
Member
 
Registered: Nov 2014
Posts: 399

Rep: Reputation: Disabled
I should add that I don't think it is a good idea to do this in anything but trivial code where I don't care about the state of the input. There are too many other solutions such as setting a variable in the signal handler and responding to it after returning from the fgets however that's not what the OP asked for.
 
Old 12-05-2014, 03:52 PM   #11
mina86
Member
 
Registered: Aug 2008
Distribution: Debian
Posts: 517

Rep: Reputation: 229Reputation: 229Reputation: 229
Quote:
Originally Posted by SoftSprocket View Post
Longjmp can be safely used and it can be safely used in signal handlers.
I'm not saying longjmp cannot be used from signal handlers. I'm saying your solution to OP's problem is incorrect and provided code that demonstrates that.

Quote:
Originally Posted by SoftSprocket View Post
however that's not what the OP asked for.
I also don't think OP asked for a solution where data can be dropped.

Last edited by mina86; 12-05-2014 at 03:53 PM.
 
Old 12-08-2014, 01:22 AM   #12
user@123
LQ Newbie
 
Registered: Mar 2014
Posts: 18

Original Poster
Rep: Reputation: Disabled
Thanks @SoftSprocket for your response but this is working for one time means second time on words sigint_handler is not getting called.
For first time program runs and when i press ctrl+c "Hello, sigint!" is printed on stout after that program is waiting for user to give input but second time on words message is not displayed and program is waiting for input.
I visited this link http://www.csl.mtu.edu/cs4411.ck/www...oto/sig-1.html here also i am facing same problem signal handler is executed only on pressing ctrl+c for first time.

Last edited by user@123; 12-08-2014 at 03:33 AM. Reason: Added references.
 
Old 12-08-2014, 04:46 AM   #13
user@123
LQ Newbie
 
Registered: Mar 2014
Posts: 18

Original Poster
Rep: Reputation: Disabled
Solved my problem using sigsetjmp and siglongjmp.
 
Old 12-08-2014, 08:09 AM   #14
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,864
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
Note: using setjmp/longjmp is essencially the same thing as ON ERROR GOTO in BASIC, exceptions in C++/Java/Ada, FCB.EXLST in System/360 Assembly. I wouldn't use any of them, if I could avoid.
 
  


Reply

Tags
blocking, signal, signal handler



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
kernel rtcw Received signal 11, exiting forum1793 Slackware 4 07-21-2008 06:21 PM
Program received signal SIGABRT, Aborted. barbuceanu Linux - Software 3 07-03-2008 08:13 AM
received signal 11 ligne Linux - Software 8 07-28-2005 05:10 PM
received signal 11, exiting.... sortebo Linux - Software 3 06-23-2003 03:42 AM
received Signal 7 ????? sachinkatak Linux - Hardware 2 06-17-2002 04:31 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 10:28 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration