read stdout/stderr without blocking

Grant Edwards grante at visi.com
Tue Sep 13 10:46:12 EDT 2005


On 2005-09-13, Jacek Pop?awski <jpopl at interia.pl> wrote:
> Grant Edwards wrote:
>> You're right.  I must have been remembering the behavior of a
>> network socket.  Apparently, you're supposed to read a single
>> byte and then call select() again.  That seems pretty lame.
>
> I created another thread with single read(), it works, as long
> as I have only one PIPE (i.e. stderr is redirected into
> stdout). I wonder is it Python limitation or systems one (I
> need portable solution)?

Not sure what you mean.  Here is my test program that blocks on
the read(1024) call:

#!/usr/bin/python
import os,select

p = os.popen("while sleep 2; do date; done","r")
print p

while 1:
    r,w,e = select.select([p],[],[],1)
    if r:
        d = r[0].read(1024)
        print len(d),repr(d)
    else:
        print "timeout"

It also blocks if the call is changed to read().  This seems
pretty counter-intuitive, since that's not the way read()
usually works on pipes.
        
Here's the corresponding C program that works as I
expected (read(1024) returns available data):

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/select.h>

unsigned char buffer[1024];
int main(void)
{
  fd_set readfds, writefds, exceptfds;
  struct timeval tv;
  FILE *fp;
  int fd;
  
  fp = popen("while sleep 2; do date; done","r");
  if (!fp)
    {
      perror("popen");
      exit(1);
    }
  fd = fileno(fp);
  
  FD_ZERO(&readfds);
  FD_ZERO(&writefds);
  FD_ZERO(&exceptfds);
  
  while (1)
    {
      int s;
      FD_SET(fd,&readfds);
      tv.tv_sec = 1;
      tv.tv_usec = 0;
      s = select(fd+1,&readfds,&writefds,&exceptfds,&tv);
      if (s==0)
        printf("timeout\n");
      else if (s<0)
        {
          perror("select");
          exit(2);
        }
      else
        {
          if FD_ISSET(fd,&readfds)
            {
              int n = read(fd,buffer,(sizeof buffer)-1);
              buffer[n] = '\0';
              printf("read %d: '%s'\n",n,buffer);
            }
        }
    }
}


-- 
Grant Edwards                   grante             Yow!  Does that mean
                                  at               I'm not a well-adjusted
                               visi.com            person??



More information about the Python-list mailing list