Kevin Brosius on Mon, 24 Jun 2002 14:40:09 +0200


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

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


"Michael F. Robbins" wrote:
> 
> 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?
> 
> Here's the code in question:
> ------
> // includes omitted for sanity
> 
> int main(int argc, char *argv[])
> {
>   ifstream fifoIn("/path/to/fifo");
>   int fifoInID = fifoIn.rdbuf()->fd();
>   pollfd fifoInPollFD = {0, 0, 0};
>   fifoInPollFD.fd = fifoInID;
>   fifoInPollFD.events = POLLIN;
> 
>   char lastCommandC[1024];
>   String lastCommand;
> 
>   while(1) {
>     // Other stuff must be free to happen here
>     // if there are no new commands
> 
>     // Check for tasks on message queue and process them.
>     fifoInPollFD.events = POLLIN;
>     fifoInPollFD.revents = 0;
> 
>     // 10 millisecond timeout
>     if(poll(&fifoInPollFD, 1, 10) > 0) {
> 
>       // Grab a line, stick it in lastCommandC, and
>       // convert it to a String class
>       fifoIn.getline(lastCommandC, sizeof lastCommandC, '\n');
>       lastCommandC[sizeof lastCommandC - 1] = '\0';
>       lastCommand = lastCommandC;
> 
>       // No, this is not the error.  The dispatch function
>       // is defined and works well.
>       cerr << "Dispatch: " << lastCommand << endl;
>       dispatch(lastCommand);
> 
>       if(fifoIn.eof()) {
>         cerr << "eof on input fifo" << endl;
>         exit(0);
>       }
>     }
>   } // close while loop
>   return 0;
> }

Does the eof flag get set after you use getline when only a single line
is available?  I'd assume you could loop on the eof flag to read
multiple lines from the stream.

Although considering this a little more, that depends on the iostream
class behavior.  You might be better off looping on getline, and
assuming the stream is empty when the return string is zero length.

The documentation I just looked at
(http://www.cplusplus.com/ref/iostream/istream/getline.html) doesn't
give enough info to determine which way will work.  If you have better
docs you should be able to tell, or a couple tests cases can prove it
for you.

-- 
Kevin Brosius

______________________________________________________________________
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