views:

91

answers:

1

I'm working on a program that uses an epoll-based event loop to handle multiple simultaneous socket connections. When the app detects that there is data to be read, it calls a process_request() sub, which uses buffered IO. For example:

sub process_request {
    my ( $fh ) = @_;
    if ( my $line = <$fh> ) {
        # Do something interesting
    }
}

The trouble is that by using buffered I/O here, epoll doesn't know that there's unread data waiting in the buffer, so it doesn't call process_request() again.

So the question is, how can I detect if there is unread data in filehandle in Perl, so that I can call process_request() again as long as data remains in the buffer?

+1  A: 

Well I know that you're using your own event loop, and not POE, but you might want to borrow POE's filters anyway; they can be loaded without using the rest of POE. Initialize a POE::Filter::Line per socket, and when a socket comes readable do a nonblocking read for all it has, and push them into the filter with $filter->get. The return will be an arrayref of (0 or more) lines, and any partial lines will be stored in the filter, awaiting the rest of the line.

If that doesn't appeal, well, you could always reimplement the same idea yourself. It's not a huge amount of work, mostly a string buffer per-socket and a regex match.

hobbs
That would change the API contract... but perhaps by doing that along with Tie::Handle I can accomplish what I need.
Flimzy
I'm assuming the problem is that you have to share the handle with something else that couldn't stand to have its data potentially swallowed by the filter? Because the only significant change in the way things work is that data is left in the filter's buffer instead of the socket's. If that's the case I think you're on the right track -- but keep in mind that you can probably just use an object (maybe subclassing IO::Handle or IO::Socket) rather than the ugly tie interface. :)
hobbs