problem with using select() to check stdin

problem with using select() to check stdin

Post by Joe Humrickhou » Wed, 17 Nov 1999 04:00:00



I am playing around trying to get my program to read a keypress and then exit.
I have already checked the UNIX Programming FAQ and it was pretty helpful for
getting my program to read in one character.  I was looking at an example
program that used pretty much the same code the FAQ did using termios to set
the terminal into raw mode, but I also noticed that they used select() to check
stdin for new input.  I am trying to get my program to do that, but I am not
having very much luck.  What am I doing wrong with select, it appears to be
looping ad nauseum and never getting to the break even when I am hammering on
my keyboard.  The program did what I wanted it to when I was just using the
set_keypress() function from the FAQ without select().  Should I be using
select() or is the set_keypress function already taking care of everything?  
It seems that I could not use select() and be find, but would I run into any
complications?  Thanks!

Sorry if this is a little long:

#include <stdlib.h>
#include <stdio.h>
#include <termios.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

void set_keypress(void);
void reset_keypress(void);

static struct termios stored_settings;

main()
{
        int c;
        fd_set set;
        struct timeval tv;
        int fd_status;

        set_keypress();

        FD_ZERO(&set);
        FD_SET(0, &set);
        tv.tv_sec = 0;
        tv.tv_sec = 0;

        for(;;) {              
                fd_status = select(1, &set, NULL, NULL, &tv);
                if (FD_ISSET(0, &set))
                        break;
        }

        read(0, &c, 1);
        printf("%c\n", c);

        reset_keypress();

        exit(0);

Quote:}

void set_keypress(void)
{
    struct termios new_settings;

    tcgetattr(0,&stored_settings);

    new_settings = stored_settings;

    /* Disable canonical mode, and set buffer size to 1 byte */
    new_settings.c_lflag &= ~(ICANON | ECHO);
    new_settings.c_cc[VTIME] = 0;
    new_settings.c_cc[VMIN] = 1;

    tcsetattr(0,TCSANOW,&new_settings);
    return;

Quote:}

void reset_keypress(void)
{
    tcsetattr(0,TCSANOW,&stored_settings);
    return;

Quote:}

--
Joe Humrickhouse

 
 
 

problem with using select() to check stdin

Post by Ross Crawfor » Wed, 17 Nov 1999 04:00:00



Quote:> I am playing around trying to get my program to read a keypress and then
exit.
> I have already checked the UNIX Programming FAQ and it was pretty helpful
for
> getting my program to read in one character.  I was looking at an example
> program that used pretty much the same code the FAQ did using termios to
set
> the terminal into raw mode, but I also noticed that they used select() to
check
> stdin for new input.  I am trying to get my program to do that, but I am
not
> having very much luck.  What am I doing wrong with select, it appears to
be
> looping ad nauseum and never getting to the break even when I am hammering
on
> my keyboard.  The program did what I wanted it to when I was just using
the
> set_keypress() function from the FAQ without select().  Should I be using
> select() or is the set_keypress function already taking care of
everything?
> It seems that I could not use select() and be find, but would I run into
any
> complications?  Thanks!

[snip]

> FD_ZERO(&set);
> FD_SET(0, &set);
> tv.tv_sec = 0;
> tv.tv_sec = 0;

> for(;;)
> fd_status = select(1, &set, NULL, NULL, &tv);
> if (FD_ISSET(0, &set))
> break;
> }

Joe,

This is a mistake I made on my first attempt.

Looking at your logic, you can see that if the FD_ISSET returns false, the
set[0] element is no longer set, so the next time select() is called, fd 0
(stdin) is no longer checked. You should move the FD_ZERO & FD_SET inside
the loop, before the select() call.

HTH

ROSCO