Messages in this thread | | | Date | Sun, 17 Oct 1999 09:02:01 +0200 | From | Natapov Gleb <> | Subject | Re: /dev/random and nonblocking I/O bug ? |
| |
tytso@mit.edu wrote: > > Date: Tue, 12 Oct 1999 16:09:10 +0200 > From: Natapov Gleb <gnatapov@qualcomm.com> > > It seems that read from /dev/random can block even if the device was > opened with O_NONBLOCK flag. > > Umm, no, it doesn't block for me....
I can recreate this bug on each and every Linux box. If you want see this program blocks you should check the following things: 1) The entropy pool should be full (this condition is not essential for bug to appear, but it just increase probability to have context switch while execution of random_read) 2) You must not use any device that generate interrupts while running the program. Each interrupt cause add_interrupt_randomness function to be called and this function wakes up all processes form random_read_wait queue. Thus, if you have any device that constantly generate interrupts (for instance you download something from the network, or listening to mp3), you can't notice that process moves from running queue and back because it does this very very fast.
I'd, actually, had problem recreate this bug at my home computer until i've found that one program, that I run in startup, make my ide1 controller (I have cdrom there) generate interrupt several time per second. After killing this program the bug was easily recreatable.
> > I wrote the following program: > ================================================================= > #include <errno.h> > #include <unistd.h> > #include <sys/types.h> > #include <sys/stat.h> > #include <fcntl.h> > #include <stdio.h> > > void main() > { > int randfd; > char c; > if( (randfd = open("/dev/random", O_RDONLY | O_NONBLOCK)) >= 0){ > while(1){ > if(read(randfd, &c, 1) != 1){ > if( errno != EWOULDBLOCK && errno != 0 ) > fprintf(stderr, "read error form random device"); > break; > } > fprintf(stderr,"."); > } > } > } > ===================================================================== > > This program is broken. Once you exhaust the pool of available > entropy, read will return 0, and errno will be set to EAGAIN (aka > EWOULDBLOCK). > Why do you think that this program is broken. It checks errno if read failed to read 1 byte and if errno is EWOULDBLOKC it exits. This program shouldn't block anyway.
> If the random pool is empty and O_NONBLOCK is set it returns EAGAIN (as > we are expecting) else it calls extract_entropy(). > > No, it doesn't return EAGAIN; it breaks from the while loop, and after > the whole loop current->state is set back to TASK_RUNNING before it > returns. > Yes, you are right, but I was talking about my program. It tries to read only one byte of data and if one byte is not available it breaks from the while loop, current->state is set to TASK_RUNNING and EAGAIN is returned.
Anyway, If you can't recreate this bug on you computer lets look at the code: This is the pseudo code for random_read and extract_entropy (I've dropped not relevant details).
random_read(...,char * buf, size_t nbytes,...) { add current to random_read_wait while(nbytes > 0){ current->state = TASK_INTERRUPTIBLE; if (there is no enough entropy in entropy pool){ if(nonblocking i/o) breaks from loop else scheduler(); } /* If we are here - there is at least one byte of entropy in the entropy pool and current->state == TASK_INTERRUPTIBLE*/ call extract_entropy; } current->state = TASK_RUNNING; remove current from random_read_wait return; }
extract_entroy(...,char * buf,...) { write available entropy to buffer; /*XXX*/ if(current->need_resched == 1) scheduler(); }
If at the point marked /*XXX*/ time interrupt is happened and changes current->nedd_resched to 1 the process goes to sleep until next non-timer interrupt.
Gleb.
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |