views:

746

answers:

4

I need my program written in pure C to stop execution when stdin is closed.

There is indefinite work done in program main cycle, and there is no way I can use blocking checks (like getc()) there (no data is supposed to arrive on stdin - it just stays opened for unknown time).

I intend to use described functionality in realization of network daemon hosted in inetd, xinetd or their analogs - it should emit data on stdout while connection stays opened and correctly finish work when it closes. Now my program is killed by hosting service as it won't stop after connection termination.

I wonder if fctntl() with O_NONBLOCK flag applied to stdin descriptor would allow me to use read() function in non-blocking mode? Should I use select() somehow?

P.S. The data is not supposed but might arrive to stdin. A way of non-blocking readout woould be an answer for the question.

A: 

What's wrong with feof(stdin) ?

eduffy
That won't work if you don't read out all data. How do I read out all data (trash for example) without blocking operations?
Basilevs
+1  A: 

I'm not sure whether you can set O_NONBLOCK on stdin, but select() or poll() will definitely get the job done.

Michael Foukarakis
Yes, you can set O_NONBLOCK on stdin. If your stdin is piped from another program, though, that program may not handle its outbound file descriptor becoming non-blocking very well.
ephemient
A: 

Yes, you can use select (with a zero timeout). You don't need to set the file descriptor non-blocking, though - if select tells you that the file descriptor is readable, then a read on it will definitely not block.

So, poll file descriptor 0 occaisionally with select, and if it's readable, read it. If read returns 0, then that means it's been closed.

caf
+2  A: 

select() does exactly what you want: signal that an operation (read, in this case) on a file descriptor (file, socket, whatever) will not block.

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

int is_ready(int fd) {
    fd_set fdset;
    struct timeval timeout;
    int ret;
    FD_ZERO(&fdset);
    FD_SET(fd, &fdset);
    timeout.tv_sec = 0;
    timeout.tv_usec = 1;
    return select(1, &fdset, NULL, NULL, &timeout) == 1 ? 1 : 0;
}

You can now check a file descriptor before use, for instance in order to empty the file descriptor:

void empty_fd(int fd) {
    char buffer[1024];
    while (is_ready(fd)) {
        read(fd, buffer, sizeof(buffer));
    }
}

In your case, use fileno(stdin) to get the file descriptor of stdin:

if (is_ready(fileno(stdin))) {
    /* read stuff from stdin will not block */
}
digitalarbeiter
`poll` is also exactly what OP wants, and its interface is a bit easier than `select` when dealing with a small, fixed set of file descriptors.
ephemient