LinuxQuestions.org
Share your knowledge at the LQ Wiki.
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
 
LinkBack Search this Thread
Old 11-04-2009, 07:39 AM   #1
crs_zxf
Member
 
Registered: Oct 2008
Distribution: Arch Linux
Posts: 37

Rep: Reputation: 17
send signal every time input comes in on stdin


Problem solved, I ont only find the answer, but learn much else.

Hi guys.

how to inform OS to send a signal like SIGIO every time input comes in on stdin, I tried to use ioctl and fcntl, but both failed, so can anyone help me figure it out, thanks!

Last edited by crs_zxf; 11-08-2009 at 07:03 AM.
 
Old 11-04-2009, 07:46 AM   #2
JohnGraham
Member
 
Registered: Oct 2009
Posts: 401

Rep: Reputation: 113Reputation: 113
Quote:
Originally Posted by crs_zxf View Post
Hi guys.

I want to write a program which sends a signal like SIGIO every time input comes in on stdin, I tried to use ioctl and fcntl, but both failed, so can anyone help me figure it out, thanks!
So long as you know how to read from stdin, all you need to complete the Astounding Chain Of Glory is kill() - see the man page in section 2, or http://linux.die.net/man/2/kill.

John G
 
Old 11-04-2009, 07:57 AM   #3
crs_zxf
Member
 
Registered: Oct 2008
Distribution: Arch Linux
Posts: 37

Original Poster
Rep: Reputation: 17
Quote:
Originally Posted by JohnGraham View Post
So long as you know how to read from stdin, all you need to complete the Astounding Chain Of Glory is kill() - see the man page in section 2, or http://linux.die.net/man/2/kill.

John G
Sorry, I wrote my question wrongly, what I mean is how to inform OS to send me a signal every time there's a input on stdion
 
Old 11-05-2009, 03:29 AM   #4
JohnGraham
Member
 
Registered: Oct 2009
Posts: 401

Rep: Reputation: 113Reputation: 113
Quote:
Originally Posted by crs_zxf View Post
Sorry, I wrote my question wrongly, what I mean is how to inform OS to send me a signal every time there's a input on stdion
I don't know of a way to do this, except to read standard input using getchar() or scanf() and send the signal yourself with kill().

Note that (i) scanf() is unsafe, as it pays no attention to how large a buffer you've assigned it, so if you try and read a string and the user enters a string that's too long, your data will get stomped on, and (ii) input from stdin is buffered - maybe there's a ways you can make it unbuffered, but unless you do that, you'll only get told about things on stdin when the user presses the return key.

John G
 
Old 11-05-2009, 07:59 PM   #5
crs_zxf
Member
 
Registered: Oct 2008
Distribution: Arch Linux
Posts: 37

Original Poster
Rep: Reputation: 17
Quote:
Originally Posted by JohnGraham View Post
(i) scanf() is unsafe, as it pays no attention to how large a buffer you've assigned it, so if you try and read a string and the user enters a string that's too long, your data will get stomped on
So what do you generally use to input a string? through command line argument?

Quote:
Originally Posted by JohnGraham View Post
(ii) input from stdin is buffered - maybe there's a ways you can make it unbuffered, but unless you do that, you'll only get told about things on stdin when the user presses the return key.
Actually, command "stty raw" can disable those line-editing characters like backspace, if you have a "getchar()", then after you press a key, it will immediately be accepted as input without pressing enter. (But if you want to input a string, you still need to press enter).

To reenable line-editing mode, run "stty cooked".

Thanks for your tips.
 
Old 11-05-2009, 08:34 PM   #6
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: Debian lenny, Slackware 12
Posts: 805

Rep: Reputation: 161Reputation: 161
Quote:
Originally Posted by crs_zxf View Post
how to inform OS to send a signal like SIGIO every time input comes in on stdin, I tried to use ioctl and fcntl, but both failed, so can anyone help me figure it out, thanks!
You tried fcntl with F_SETOWN, yes? That should work. Can you show a simple test program that fails?
 
Old 11-06-2009, 05:33 AM   #7
crs_zxf
Member
 
Registered: Oct 2008
Distribution: Arch Linux
Posts: 37

Original Poster
Rep: Reputation: 17
Quote:
Originally Posted by wje_lq View Post
You tried fcntl with F_SETOWN, yes? That should work. Can you show a simple test program that fails?
yeah, F_SETOWN does work, but something strange happen when you run the following code:

Code:
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>

void
sig_io(int signo)
{
        char c = 0;

        c = getchar();
        if (c == 'q') {
                exit(0);
        }
        printf("read character %c\n", c);
}

int
main(int argc, char **argv)
{
        struct sigaction sa;

        memset(&sa, 0, sizeof(sa));
        sa.sa_handler = sig_io;

        if (sigaction(SIGIO, &sa, NULL) < 0) {
                fprintf(stderr, "[ERROR]: sigaction error\n");
                exit(1);
        }

        if (fcntl(0, F_SETFL, O_ASYNC) < 0) {
                fprintf(stderr, "[ERROR]: fcntl error for O_ASYNC\n");
                exit(1);
        }

        if (fcntl(0, F_SETOWN, getpid()) < 0) {
                fprintf(stderr, "[ERROR]: fcntl F_SETOWN error\n");
                exit(1);
        }

        while (1) {
                printf("1");
        }

        return 0;
}
I think the normal result is that it keeps printing "1", and when you press a key followed by return, it prints "read character ..", and then start printing "1" again.

But actually the result is it prints some "1", and then stop, waiting for you to input a chacacter, and once you input a character, it prints some "1" again, and waiting for you to input again, and this goes on and on until you terminate it by pressing 'q' or Ctrl-C.

So why?

Last edited by crs_zxf; 11-06-2009 at 05:50 AM.
 
Old 11-07-2009, 05:19 AM   #8
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: Debian lenny, Slackware 12
Posts: 805

Rep: Reputation: 161Reputation: 161
First, you should be cautious about the library function calls you make in a signal handler. getchar()? No. exit()? No (although _exit() is ok). printf()? No.

To get a list of functions you can safely use in a signal handler, do this at the shell command prompt:
Code:
man 7 signal
... and then scroll down many, many pages.

Here are three programs which do what you want. The first is the simplest. The second, though more complex, might be more appealing because it shows the main loop's awareness of time passing. The third shows your stream of "1". The problem with that one is that it's difficult to notice the reporting of characters input, because it rapidly scrolls off the screen. You can find that reporting in the verbose "1" stream by running the whole thing within a script command, and examining the output with grep or less or vi or some other editor.

You'll notice that each is a shell script.

But before the three scripts, here is typical output of the first two.
Code:
aread character a
bread character b
cread character c
dread character d
eread character e
qgot quit request
major loop count: 2086205662
signals caught  : 12
characters input: 5
Code:
11aread character a
11bread character b
111cread character c
1dread character d
1eread character e
1qgot quit request
major loop count: 32203501
signals caught  : 22
characters input: 5
Code:
rm -f 2; cat > 2.c <<EOD; gcc -Werror -Wall 2.c -o 2; stty raw; ./2; stty sane;
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>

#include <sys/select.h>      /* added by wje */

volatile long long count_major_loop      =0;
volatile long long count_signals_caught  =0;
volatile long long count_characters_input=0;
volatile int       flag_quit             =0;

size_t
length(const char *something)
{
        size_t result=0;

        while(*something++) {
                result++;
        }

        return result;
}

void
sig_io(int signo)
{
        ssize_t        read_count;

        char           c_array[4];

        fd_set         read_set;

        struct timeval timeout_value;

        count_signals_caught++;

        FD_ZERO(&read_set);

        FD_SET(STDIN_FILENO,&read_set);

        timeout_value.tv_sec =0;
        timeout_value.tv_usec=0;

        if(select(STDIN_FILENO+1,&read_set,NULL,NULL,&timeout_value)>0)
        {
                read_count=read(STDIN_FILENO,c_array,1);

                if(read_count < 0) {
                        write(STDERR_FILENO,"got error\r\n",
                                     length("got error\r\n"));
                        flag_quit=1;
                }
                else
                if(read_count==0)
                {
                        write(STDERR_FILENO,"got eof\r\n",
                                     length("got eof\r\n"));
                        flag_quit=1;
                }
                else
                if (c_array[0] == 'q') {
                        write(STDERR_FILENO,"got quit request\r\n",
                                     length("got quit request\r\n"));
                        flag_quit=1;
                }
                else
                {
                        count_characters_input++;

                        write(STDOUT_FILENO,"read character ",
                                     length("read character "));

                        write(STDOUT_FILENO,c_array,1);

                        write(STDOUT_FILENO,"\r\n",
                                     length("\r\n"));
                }
        }
}

int
main(int argc, char **argv)
{
        struct sigaction sa;

        memset(&sa, 0, sizeof(sa));
        sa.sa_handler = sig_io;

        if (sigaction(SIGIO, &sa, NULL) < 0) {
                fprintf(stderr,"[ERROR]: sigaction error\n");
                exit(1);
        }

        if (fcntl(0, F_SETOWN, getpid()) < 0) {
                fprintf(stderr,"[ERROR]: fcntl F_SETOWN error\n");
                exit(1);
        }

        if (fcntl(0, F_SETFL, O_NONBLOCK|O_ASYNC) < 0) {
                fprintf(stderr,"[ERROR]: fcntl error for O_NONBLOCK|O_ASYNC\n");
                exit(1);
        }

        while (!flag_quit) {
                count_major_loop++;
        }

        printf("major loop count: %lld\r\n",count_major_loop      );
        printf("signals caught  : %lld\r\n",count_signals_caught  );
        printf("characters input: %lld\r\n",count_characters_input);

        return 0;
}
EOD
Code:
rm -f 3; cat > 3.c <<EOD; gcc -Werror -Wall 3.c -o 3; stty raw; ./3; stty sane;
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>

#include <sys/select.h>      /* added by wje */
#include <time.h>            /* added by wje */

volatile long long count_major_loop      =0;
volatile long long count_signals_caught  =0;
volatile long long count_characters_input=0;
volatile int       flag_quit             =0;

size_t
length(const char *something)
{
        size_t result=0;

        while(*something++) {
                result++;
        }

        return result;
}

void
sig_io(int signo)
{
        ssize_t        read_count;

        char           c_array[4];

        fd_set         read_set;

        struct timeval timeout_value;

        count_signals_caught++;

        FD_ZERO(&read_set);

        FD_SET(STDIN_FILENO,&read_set);

        timeout_value.tv_sec =0;
        timeout_value.tv_usec=0;

        if(select(STDIN_FILENO+1,&read_set,NULL,NULL,&timeout_value)>0)
        {
                read_count=read(STDIN_FILENO,c_array,1);

                if(read_count < 0) {
                        write(STDERR_FILENO,"got error\r\n",
                                     length("got error\r\n"));
                        flag_quit=1;
                }
                else
                if(read_count==0)
                {
                        write(STDERR_FILENO,"got eof\r\n",
                                     length("got eof\r\n"));
                        flag_quit=1;
                }
                else
                if (c_array[0] == 'q') {
                        write(STDERR_FILENO,"got quit request\r\n",
                                     length("got quit request\r\n"));
                        flag_quit=1;
                }
                else
                {
                        count_characters_input++;

                        write(STDOUT_FILENO,"read character ",
                                     length("read character "));

                        write(STDOUT_FILENO,c_array,1);

                        write(STDOUT_FILENO,"\r\n",
                                     length("\r\n"));
                }
        }
}

int
main(int argc, char **argv)
{
        time_t           tick_tick;

        struct sigaction sa;

        memset(&sa, 0, sizeof(sa));
        sa.sa_handler = sig_io;

        if (sigaction(SIGIO, &sa, NULL) < 0) {
                fprintf(stderr,"[ERROR]: sigaction error\n");
                exit(1);
        }

        if (fcntl(0, F_SETOWN, getpid()) < 0) {
                fprintf(stderr,"[ERROR]: fcntl F_SETOWN error\n");
                exit(1);
        }

        if (fcntl(0, F_SETFL, O_NONBLOCK|O_ASYNC) < 0) {
                fprintf(stderr,"[ERROR]: fcntl error for O_NONBLOCK|O_ASYNC\n");
                exit(1);
        }

        tick_tick=time(NULL);

        while (!flag_quit) {
                if(tick_tick!=time(NULL)) {
                        tick_tick=time(NULL);
                        printf("1");
                        fflush(stdout);
                }
                count_major_loop++;
        }

        printf("major loop count: %lld\r\n",count_major_loop      );
        printf("signals caught  : %lld\r\n",count_signals_caught  );
        printf("characters input: %lld\r\n",count_characters_input);

        return 0;
}
EOD
Code:
rm -f 4; cat > 4.c <<EOD; gcc -Werror -Wall 4.c -o 4; stty raw; ./4; stty sane;
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>

#include <sys/select.h>      /* added by wje */

volatile long long count_major_loop      =0;
volatile long long count_signals_caught  =0;
volatile long long count_characters_input=0;
volatile int       flag_quit             =0;

size_t
length(const char *something)
{
        size_t result=0;

        while(*something++) {
                result++;
        }

        return result;
}

void
sig_io(int signo)
{
        ssize_t        read_count;

        char           c_array[4];

        fd_set         read_set;

        struct timeval timeout_value;

        count_signals_caught++;

        FD_ZERO(&read_set);

        FD_SET(STDIN_FILENO,&read_set);

        timeout_value.tv_sec =0;
        timeout_value.tv_usec=0;

        if(select(STDIN_FILENO+1,&read_set,NULL,NULL,&timeout_value)>0)
        {
                read_count=read(STDIN_FILENO,c_array,1);

                if(read_count < 0) {
                        write(STDERR_FILENO,"got error\r\n",
                                     length("got error\r\n"));
                        flag_quit=1;
                }
                else
                if(read_count==0)
                {
                        write(STDERR_FILENO,"got eof\r\n",
                                     length("got eof\r\n"));
                        flag_quit=1;
                }
                else
                if (c_array[0] == 'q') {
                        write(STDERR_FILENO,"got quit request\r\n",
                                     length("got quit request\r\n"));
                        flag_quit=1;
                }
                else
                {
                        count_characters_input++;

                        write(STDOUT_FILENO,"read character ",
                                     length("read character "));

                        write(STDOUT_FILENO,c_array,1);

                        write(STDOUT_FILENO,"\r\n",
                                     length("\r\n"));
                }
        }
}

int
main(int argc, char **argv)
{
        struct sigaction sa;

        memset(&sa, 0, sizeof(sa));
        sa.sa_handler = sig_io;

        if (sigaction(SIGIO, &sa, NULL) < 0) {
                fprintf(stderr,"[ERROR]: sigaction error\n");
                exit(1);
        }

        if (fcntl(0, F_SETOWN, getpid()) < 0) {
                fprintf(stderr,"[ERROR]: fcntl F_SETOWN error\n");
                exit(1);
        }

        if (fcntl(0, F_SETFL, O_NONBLOCK|O_ASYNC) < 0) {
                fprintf(stderr,"[ERROR]: fcntl error for O_NONBLOCK|O_ASYNC\n");
                exit(1);
        }

        while (!flag_quit) {
                printf("1");
                fflush(stdout);
                count_major_loop++;
        }

        printf("major loop count: %lld\r\n",count_major_loop      );
        printf("signals caught  : %lld\r\n",count_signals_caught  );
        printf("characters input: %lld\r\n",count_characters_input);

        return 0;
}
EOD
 
Old 11-08-2009, 02:56 AM   #9
crs_zxf
Member
 
Registered: Oct 2008
Distribution: Arch Linux
Posts: 37

Original Poster
Rep: Reputation: 17
Quote:
Originally Posted by wje_lq View Post
First, you should be cautious about the library function calls you make in a signal handler ... ...
Thanks very much for your greate responce, I learn much from it, they really work as expected. But I still have one problem, I found that the number of signals caught is larger than the number of input characters, and in the 3rd program, the difference is actually huge, and that means even if there's no keypress event, SIGIO will be sent. Then I refered to the manpage of fcntl, from which I learned that using F_SETOWN command means SIGIO will be sent whenever there's an event on the given file descriptor, so except the keypress event, what other things happened on stdin?

Thanks!

Last edited by crs_zxf; 11-08-2009 at 02:57 AM.
 
Old 11-08-2009, 03:58 AM   #10
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: Debian lenny, Slackware 12
Posts: 805

Rep: Reputation: 161Reputation: 161
Quote:
Originally Posted by crs_zxf View Post
using F_SETOWN command means SIGIO will be sent whenever there's an event on the given file descriptor, so except the keypress event, what other things happened on stdin
When you run these scripts without redirecting the output, then stdin, stdout, and stderr are actually the same device. So the other thing that happens is that output is done. After output is done, a new event occurs to show that more output can be done without blocking.

Of course, you can't tell whether the signal is happening because input has arrived or because output is possible without blocking. Distinguishing these is the purpose of the select().
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

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
Trackbacks are Off
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Input Signal Out of Range Jongi Linux - General 6 05-18-2008 07:43 AM
How to make extra stdin input in awk ? khaan Programming 3 07-30-2007 05:04 AM
Send EOF to stdin? (C) smoothdogg00 Programming 3 03-07-2006 07:10 PM
no signal when starting xorg for the 1st time (but the second time works fine) bungalowbill Linux - Software 0 06-04-2004 09:56 AM
input signal out of range tadspurgeon Linux - Software 4 01-30-2004 11:50 AM


All times are GMT -5. The time now is 10:53 AM.

Main Menu
 
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
identi.ca: @linuxquestions
Facebook: @linuxquestions
Open Source Consulting | Domain Registration