2011-05-02 16 views
11

Próbuję napisać program, w którym mam oglądać końce niektórych nazwanych rur za pomocą funkcji poll. Mam pętlę for do sprawdzenia każdej rury, gdy sonda zwraca> 0 i wiem, że gdy rura zostanie zamknięta z procedury na drugim końcu, dostanę POLLHUP lub POLLIN | POLLHUP w polu revents struktury pollfd.Jak używać funkcji ankiety C do oglądania nazwanych potoków w systemie Linux?

Moje pytanie brzmi: kiedy jedna rura rzeczywiście się zamyka i zwraca mi POLLHUP, co stanie się w następnej pętli? Czy wraca ponownie do POLLHUP w następnej i dowolnej kolejnej pętli, czy też funkcja ankieta zignoruje ją po pierwszym POLLHUP?

+5

brzmi jak byłoby to dość proste, aby dowiedzieć się, sprawdzając je. –

+0

próbowałem, ale coś poszło nie tak i pollhup powraca zbyt wiele razy, znacznie więcej niż się spodziewano, więc zastanawiałem się, co może być nie tak z moim kodem, więc zadałem to pytanie: – nikos

+2

@nikos: Prawdopodobnie chcesz powiedzieć, że nie masz dłużej zainteresowanych wydarzeniami z tego fd (lub tylko niektórymi zdarzeniami, jeśli połączenie jest na pół zamknięte). –

Odpowiedz

1

Minimal przykład

Źródło poniżej. Zastosowanie:

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

Na innej powłoce:

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

wyjściowa:

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

więc zauważyć, jak poll czeka na odczytuje bez pętli.

Cooler przykład:

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

0 dostaje napisane co sekundę, a 1 co dwie sekundy, co pokazuje, jak poll() ma do czynienia z obu wejść jednocześnie, bez przeciągnięcia siebie.

Źródło:

#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; 
      } 
     } 
    } 
} 

skompilować z:

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

Testowany w Ubuntu 14.04.

GitHub upstream.

Aby odpowiedzieć na oryginalne pytanie:

kiedy jedna rura rzeczywiście dostać zamknięte i zwraca POLLHUP do mnie, co wydarzy się na następnej pętli? Czy wraca ponownie do POLLHUP w następnej i dowolnej kolejnej pętli, czy też funkcja ankieta zignoruje ją po pierwszym POLLHUP?

Usuń wiersze:

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

i widać, że pętle zawsze nad POLLHUP.

Usuń tylko:

close(pfds[i].fd); 

i masz POLLNVAL zamiast, jak to próbuje użyć zamkniętą fd: Linux socket handling revents POLLERR POLLHUP POLLNVAL

Powiązane problemy