Skip to contentSkip to conversation

Select with device and stdin not working

DISCUSSION M. Tavasti 4 participants 10 messages Jul 25, 2001 – Jul 26, 2001

lore
Share & tools
lore

M. Tavasti

author
#0 lore raw

I found this problem first time in 2.2 kernels, when doing own device driver. Then it was not an issue for me, and I suspected it's my fault. Now, with 2.4 again I tried to solve problem, but I can't find my way out of this, and looks like there in-kernel drivers which have same symptoms.

Here program where I get problems:

int fd;
fd_set rfds;

fd = open("/dev/random", O_RDWR );

while(1) {
        FD_ZERO(&rfds);
        FD_SET(fd,&rfds);
        FD_SET(fileno(stdin),&rfds);
        if( select(fd+1, &rfds, NULL, NULL, NULL  ) > 0) {
                fprintf(stderr,"Select\n");
                fflush(stderr);
                if(FD_ISSET(fd,&rfds)) {
                 .......
                } else if(FD_ISSET(fileno(stdin),&rfds) ) { 
                 ......
                }
        }
}

Select is working fine for device (in this example /dev/random) or stdin. But for both, not. When entering something to stdin, it's not sure select will return.

I haven't tested is this problem present in all devices, but at least /dev/random is infected. And if problem lies only in some of the drivers, it would be nice to know which driver haves decent implementation of poll and get others updated.

I'm not subsribed on the list, so when replying this you may consider Cc:ing me.

Signature · 1 line
M. Tavasti /  [email protected]  /   +358-40-5078254
#1 lore raw
Quoted 7 lines · M. Tavasti

Here program where I get problems:

int fd;
fd_set rfds;

fd = open("/dev/random", O_RDWR );

Quoted 14 lines
while(1) {
        FD_ZERO(&rfds);
        FD_SET(fd,&rfds);
        FD_SET(fileno(stdin),&rfds);
        if( select(fd+1, &rfds, NULL, NULL, NULL  ) > 0) {
                fprintf(stderr,"Select\n");
                fflush(stderr);
                if(FD_ISSET(fd,&rfds)) {
                 .......
                } else if(FD_ISSET(fileno(stdin),&rfds) ) {
                 ......
                }
        }
}

It looks like you are sending the original fd_set to select. Remember that it is modified in place. What is probably happening is that select returns at once when it gets something from /dev/random, and rfds is now modified to only contain this. The next time select runs, it will only be checking for input from /dev/random. You have to make a copy of rfds that is set every time, and send that instead.

Ketil

author
#2 lore raw
Quoted 5 lines · Ketil Froyn
Quoted 5 lines
while(1) {
        FD_ZERO(&rfds);
        FD_SET(fd,&rfds);
        FD_SET(fileno(stdin),&rfds);
        if( select(fd+1, &rfds, NULL, NULL, NULL  ) > 0) {

(Lines removed)

Quoted 4 lines
Quoted 1 line

}

It looks like you are sending the original fd_set to select. Remember that it is modified in place.

But one would at least expect FD_ZERO() to really clean up rfds, and after it FD_SET() is used again, for every call of select(). And this code works fine in 2.0 kernels, and also with 2.2 and 2.4 if I'm using named pipe and stdin. Therefore I have strong belief problem is not usage of select() but something else.

Signature · 1 line
M. Tavasti /  [email protected]  /   +358-40-5078254
#3 lore raw
Quoted 5 lines · M. Tavasti

But one would at least expect FD_ZERO() to really clean up rfds, and after it FD_SET() is used again, for every call of select(). And this code works fine in 2.0 kernels, and also with 2.2 and 2.4 if I'm using named pipe and stdin. Therefore I have strong belief problem is not usage of select() but something else.

Sorry, my bad. I misread your code.

Ketil

#4 lore raw
In reply to M. Tavasti
Quoted 29 lines · M. Tavasti

I found this problem first time in 2.2 kernels, when doing own device driver. Then it was not an issue for me, and I suspected it's my fault. Now, with 2.4 again I tried to solve problem, but I can't find my way out of this, and looks like there in-kernel drivers which have same symptoms.

Here program where I get problems:

int fd;
fd_set rfds;

fd = open("/dev/random", O_RDWR );

while(1) {
        FD_ZERO(&rfds);
        FD_SET(fd,&rfds);
        FD_SET(fileno(stdin),&rfds);
        if( select(fd+1, &rfds, NULL, NULL, NULL  ) > 0) {
                fprintf(stderr,"Select\n");
                fflush(stderr);
                if(FD_ISSET(fd,&rfds)) {
                 .......
                } else if(FD_ISSET(fileno(stdin),&rfds) ) {
                 ......
                }
        }
}
Quoted 8 lines

Select is working fine for device (in this example /dev/random) or stdin. But for both, not. When entering something to stdin, it's not sure select will return.

I haven't tested is this problem present in all devices, but at least /dev/random is infected. And if problem lies only in some of the drivers, it would be nice to know which driver haves decent implementation of poll and get others updated.

I also saw what I believe is a problem with select, but I haven't had time to poke around the kernel to try to understand it. In my case, the problem is that when I have raw sockets reading ethernet frames, select will not return immediately when there is a packet ready. When it does return, due to timeout, or another FD in the set being ready for action, the FD is set correctly though. My hack/kludge/work-around was to sleep for a max of 5ms, but that is not a clean, or efficient solution. Another person sent private email to me claiming that he saw the same problem, so it's likely I'm not insane on this issue :)

So, I do think there may be problems with select, but I'm not sure if it relates to your problem or not.

Ben

Quoted 11 lines

I'm not subsribed on the list, so when replying this you may consider Cc:ing me.

--
M. Tavasti / [email protected] / +358-40-5078254
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Signature · 3 lines
Ben Greear <[email protected]>          <[email protected]>
President of Candela Technologies Inc      http://www.candelatech.com
ScryMUD:  http://scry.wanfear.com     http://scry.wanfear.com/~greear
#5 lore raw
Quoted 15 lines · Ben Greear
Quoted 14 lines · M. Tavasti

I found this problem first time in 2.2 kernels, when doing own device driver. Then it was not an issue for me, and I suspected it's my fault. Now, with 2.4 again I tried to solve problem, but I can't find my way out of this, and looks like there in-kernel drivers which have same symptoms.

Here program where I get problems:

int fd;
fd_set rfds;

fd = open("/dev/random", O_RDWR );

Quoted 14 lines
Quoted 6 lines
while(1) {
        FD_ZERO(&rfds);
        FD_SET(fd,&rfds);
        FD_SET(fileno(stdin),&rfds);
        if( select(fd+1, &rfds, NULL, NULL, NULL  ) > 0) {
                fprintf(stderr,"Select\n");
Quoted 8 lines
                fflush(stderr);
                if(FD_ISSET(fd,&rfds)) {
                 .......
                } else if(FD_ISSET(fileno(stdin),&rfds) ) {
                 ......
                }
        }
}

Change:

                 } else if(FD_ISSET(fileno(stdin),&rfds) ) {
To:
                 } if(FD_ISSET(fileno(stdin),&rfds) ) {

Both of these bits can be (probably are) set.

Cheers,
Dick Johnson

Penguin : Linux version 2.4.1 on an i686 machine (799.53 BogoMips).

I was going to compile a list of innovations that could be attributed to Microsoft. Once I realized that Ctrl-Alt-Del was handled in the BIOS, I found that there aren't any.

author
#6 lore raw
Quoted 6 lines · Richard B. Johnson

Change:

                 } else if(FD_ISSET(fileno(stdin),&rfds) ) {
To:
                 } if(FD_ISSET(fileno(stdin),&rfds) ) {

Both of these bits can be (probably are) set.

You are third person to suggest that. Yes, it's good point, but doesn't make any difference. Or it makes when both device and stdin have something, stdin is read on second round.

But now there is nothing coming from device, and typing + pressing enter won't make select() return like it should.

Same binary works fine with 2.0.X kernels, or if I'm having stdin
+ pipe (named or unnamed, doesn't matter). And when trying with 2.0 kernel, system was totally same except kernel version.

Anybody, can you get select working *properly* with stdin+/dev/random? If you can, then there must be some mistake on my code.

Signature · 3 lines
M. Tavasti /  [email protected]  /   +358-40-5078254
 Poista sähköpostiosoitteesta molemmat x-kirjaimet 
     Remove x-letters from my e-mail address
#7 lore raw
Quoted 7 lines · M. Tavasti
Quoted 5 lines · Richard B. Johnson

Change:

                 } else if(FD_ISSET(fileno(stdin),&rfds) ) {
To:
                 } if(FD_ISSET(fileno(stdin),&rfds) ) {
Quoted 8 lines
Quoted 1 line

Both of these bits can be (probably are) set.

You are third person to suggest that. Yes, it's good point, but doesn't make any difference. Or it makes when both device and stdin have something, stdin is read on second round.

But now there is nothing coming from device, and typing + pressing enter won't make select() return like it should.

It works here...........

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/poll.h>
#include <errno.h>
#include <string.h>

static const char dev[]="/dev/random";

int main(int args, char *argv[])

{
    int fd, retval;
    fd_set rfds;

    if((fd = open(dev, O_RDONLY)) < 0)
    {
        fprintf(stderr, "Can't open device, %s\n", dev);
        exit(EXIT_FAILURE);
    }
    for(;;)
    {
        FD_ZERO(&rfds);
        FD_SET(fd, &rfds);
        FD_SET(STDIN_FILENO, &rfds);
        retval = select(fd+1, &rfds, NULL, NULL, NULL); 
        if(retval < 0)
            fprintf(stderr, "Error was %s\n", strerror(errno));
        printf("Return = %d\n", retval);
        if(FD_ISSET(fd, &rfds))
            printf("Input is available from %s\n", dev);
        if(FD_ISSET(STDIN_FILENO, &rfds))
            printf("Input is available from %s\n", "terminal");
    }
    if(close(fd) < 0)
    {
        fprintf(stderr, "Can't close device, %s\n", dev);
        exit(EXIT_FAILURE);
    }
    return 0;
}

Cheers,
Dick Johnson

Penguin : Linux version 2.4.1 on an i686 machine (799.53 BogoMips).

I was going to compile a list of innovations that could be attributed to Microsoft. Once I realized that Ctrl-Alt-Del was handled in the BIOS, I found that there aren't any.

author
#8 lore raw
Quoted 4 lines · Richard B. Johnson
Quoted 2 lines

But now there is nothing coming from device, and typing + pressing enter won't make select() return like it should.

It works here...........

You're testing different thing. You're not reading anything, so at least I get endlessly 'Input is available from /dev/random', and whenever you type something, also in terminal there's data available. If nobody reads data from /dev/random, of course there is data availble.

I modified your program (see end), and results: on 2.2.19 and 2.2.16 everything works ok, in 2.4.5 not, terminal input (with return) randomly makes select return. When looking from random.c, in 2.2.19 poll_wait is called once, like this:

	poll_wait(file, &random_poll_wait, wait);

And in 2.4.5:

	poll_wait(file, &random_read_wait, wait);
	poll_wait(file, &random_write_wait, wait);

I think I got idea how to do it right, make one wait queue for poll, which is woken up when read OR write queue is woken up.

So, now everybody just check your driver how does it do poll.

----

Here is modified test. Try this to get real results:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/poll.h>
#include <errno.h>
#include <string.h>

static const char dev[]="/dev/random";

int main(int args, char *argv[])

{
    int fd, retval;
    fd_set rfds;
    char buff[1024];

    if((fd = open(dev, O_RDONLY)) < 0)
    {
        fprintf(stderr, "Can't open device, %s\n", dev);
        exit(EXIT_FAILURE);
    }
    for(;;)
    {
        FD_ZERO(&rfds);
        FD_SET(fd, &rfds);
        FD_SET(STDIN_FILENO, &rfds);
        retval = select(fd+1, &rfds, NULL, NULL, NULL); 
        if(retval < 0)
            fprintf(stderr, "Error was %s\n", strerror(errno));
        printf("Return = %d\n", retval);
        if(FD_ISSET(fd, &rfds)) {
            printf("Input is available from %s\n", dev);
            read(fd,buff,1024);
        }
        if(FD_ISSET(STDIN_FILENO, &rfds)) {         
            printf("Input is available from %s\n", "terminal");
            read(STDIN_FILENO,buff,1024);            
        }
            
    }
    if(close(fd) < 0)
    {
        fprintf(stderr, "Can't close device, %s\n", dev);
        exit(EXIT_FAILURE);
    }
    return 0;
}
Signature · 3 lines
M. Tavasti /  [email protected]  /   +358-40-5078254
 Poista sähköpostiosoitteesta molemmat x-kirjaimet 
     Remove x-letters from my e-mail address
author
#9 lore raw
In reply to Richard B. Johnson
Quoted 5 lines · M. Tavasti

randomly makes select return. When looking from random.c, in 2.2.19 poll_wait is called once, like this:

	poll_wait(file, &random_poll_wait, wait);
Quoted 8 lines

And in 2.4.5:

	poll_wait(file, &random_read_wait, wait);
	poll_wait(file, &random_write_wait, wait);

I think I got idea how to do it right, make one wait queue for poll, which is woken up when read OR write queue is woken up.

After testing with my own driver, using just one poll_wait doesn't make difference in 2.4.5.

Signature · 3 lines
M. Tavasti /  [email protected]  /   +358-40-5078254
 Poista sähköpostiosoitteesta molemmat x-kirjaimet 
     Remove x-letters from my e-mail address