Kyle R . Burton on Mon, 24 Jun 2002 15:30:14 +0200


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

Re: [PLUG] C++, FIFOs, getline, and O_NDELAY


> I'm writing a c++ app to read a command stream from a fifo.  Commands
> are delimited by newlines.  The app must be able to process other tasks
> (running in a while loop) if there is no data incoming from the fifo. 
> Right now, I'm using ifstream's rdbuf()->fd() to get the file descriptor
> so I can use poll() on the fifo.  When there is a read event, I do an
> ifstream::getline() on the input stream class.  The problem occurs when
> the sending program sends two lines at once, i.e. before the listener
> task is run again.  The getline() is only called once for each poll()
> that returns positive, however sometimes really two or more getline()s
> are needed.  I would have thought that checking for the POLLIN event
> would have returned true since there were more data left to read. 
> However, my guess is that the ifstream class has an internal buffer
> which has the next command inside, so the poll() returns false.
> 
> Any ideas?  Right now I'm looking at setting O_NDELAY on the file
> descriptor.  This would certainly allow a simple read() function to work
> on it, but would the getline() work correctly?

I'm not sure you can do what you want with getline(), since it will block
untill it finds the next newline - there are 2 ways I can think of to solve
this.  The first is to use threads, have a 'getline' thread and have your
other thread do the work.  The second is to fall back to stdio functions
and make your main loop something like:

  char *buff; // and allocate some space...
  int numBytes;
  while(1) {
    if( poll() ) {
      numBytes = fillBuffer();
      if( 0 == numBytes ) {
        handleReadError();
        break;
      }
    }

    while( aLineIsAvailableInTheBuffer() ) { // look for a "\n"
      char* line = removeLineFromBuffer();
      dispatch( line );
    }
  }

Of course, there is alot left to fill in.  You'll have to check for 
buffer length in fillBuffer() and extend it if the input line is larger 
than the buffer.  All fillBuffer has to do is append to the end of the
buffer, returning the number of bytes read -- if 0 bytes are read when
poll() returned a status indicating that data was ready, then there is
probably some kind of error on the file descriptor.

removeLineFromBuffer() will have to lop off the first line, and left shift
the rest of the data in the buffer.  If there was more than 1 line available
to be read, the inner while() loop will process them all.

This is only one way to solve the problem...you might want to stress 
interactivity (reading the lines) over the processing, in which case
you'd probably want to check for data to read more often, or not process
all available lines while there is data to read...a bit more complex,
but that can be worked out.


HTH

Kyle





-- 

------------------------------------------------------------------------------
Wisdom and Compassion are inseparable.
        -- Christmas Humphreys
mortis@voicenet.com                            http://www.voicenet.com/~mortis
------------------------------------------------------------------------------

______________________________________________________________________
Philadelphia Linux Users Group       -      http://www.phillylinux.org
Announcements-http://lists.phillylinux.org/mail/listinfo/plug-announce
General Discussion  -  http://lists.phillylinux.org/mail/listinfo/plug