How to use the poll C function to watch named pipes in Linux?

后端 未结 2 1306
醉酒成梦
醉酒成梦 2021-01-04 07:12

I am trying to write a program where i am supposed to watch the ends of some named pipes using poll function. I have a for loop to check every pipe whenever poll returns >0

相关标签:
2条回答
  • 2021-01-04 07:48

    Minimal example

    Source below. Usage:

    sudo mknod poll0.tmp p
    sudo mknod poll1.tmp p
    sudo chmod 666 poll*.tmp
    ./poll.out
    

    On another shell:

    printf a > poll0.tmp
    printf b > poll1.tmp
    

    Output:

    loop
    POLLIN i=0 n=1 buf=a
    loop
    POLLHUP i=0
    loop
    POLLIN i=1 n=1 buf=b
    POLLHUP i=1
    loop
    

    So notice how poll waits for the reads without looping.

    Cooler example:

    (while true; do date; sleep 1; done) > poll0.tmp &
    (while true; do date; sleep 2; done) > poll1.tmp &
    

    0 gets written every one second, and 1 every two seconds, which shows how poll() is dealing with both inputs concurrently, without stalling each other.

    Source:

    #define _XOPEN_SOURCE 700
    #include <fcntl.h> /* creat, O_CREAT */
    #include <poll.h> /* poll */
    #include <stdio.h> /* printf, puts, snprintf */
    #include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS */
    #include <unistd.h> /* read */
    
    int main(void) {
        enum { N = 2 };
        char buf[1024], path[1024];
        int fd, i, n;
        short revents;
        struct pollfd pfds[N];
    
        for (i = 0; i < N; ++i) {
            snprintf(path, sizeof(path), "poll%d.tmp", i);
            /* O_NONBLOCK is required or else the open blocks
             * until the other side of the pipe opens. */
            fd = open(path, O_RDONLY | O_NONBLOCK);
            if (fd == -1) {
                perror("open");
                exit(EXIT_FAILURE);
            }
            pfds[i].fd = fd;
            /* Only events in this mask will be listened to.
             * However, there are also some events that are unmaskable,
             * notably POLLHUP when pipe closes! */
            pfds[i].events = POLLIN;
        }
        while (1) {
            puts("loop");
            i = poll(pfds, N, -1);
            if (i == -1) {
                perror("poll");
                exit(EXIT_FAILURE);
            }
            for (i = 0; i < N; ++i) {
                revents = pfds[i].revents;
                if (revents & POLLIN) {
                    n = read(pfds[i].fd, buf, sizeof(buf));
                    printf("POLLIN i=%d n=%d buf=%.*s\n", i, n, n, buf);
                }
                if (revents & POLLHUP) {
                    printf("POLLHUP i=%d\n", i);
    
                    /* This happens when the other side closed.
                     * This event is only cleared when we close the reader. */
    
                    /* poll won't set POLLHUP anymore once all fds are closed.
                     * Any futher polls on this will give the POLLNVAL event instead. */
                    close(pfds[i].fd);
    
                    /* negative fds are ignored. So if we negate an FD,
                     * we can both turn if off for a while, and turn it on
                     * later on by re-nagating it. */
                    pfds[i].fd *= -1;
                }
            }
        }
    }
    

    Compile with:

    gcc -o poll.out -std=c99 poll.c
    

    Tested in Ubuntu 14.04.

    GitHub upstream.

    To answer the original question:

    when one pipe does indeed get closed and returns POLLHUP to me, what will happen on the next loop? Is it going to return POLLHUP again and again in the next and any subsequent loop or is poll function going to ignore it after the first POLLHUP?

    Remove the lines:

    close(pfds[i].fd);
    pfds[i].fd *= -1;
    

    and you will see that it loops forever over POLLHUP.

    Remove just:

    close(pfds[i].fd);
    

    and you get POLLNVAL instead, as it tries to use a closed fd: Linux socket handling revents POLLERR POLLHUP POLLNVAL

    0 讨论(0)
  • 2021-01-04 07:58

    It will continue to set POLLHUP in revents.
    Also, see http://linux.die.net/man/3/poll for reference.

    0 讨论(0)
提交回复
热议问题