2017-10-13 20 views
0

J'ai un code qui ressemble à ceci:epoll_wait semble rester coincé sur EPOLLRDHUP

for (;;) { 
     errno=0; 
     epoll_event e = {}; 
     auto wait_r = epoll_wait(g.epoll_fd, &e, 1, 0); 
     if (wait_r==0) break; 
     if(wait_r ==-1 && errno==EINTR) { 
      printf("got EINTR\n"); 
      continue; 
     } 
     assert(wait_r == 1); 

     auto& c = *(Context*)e.data.ptr; 

     if(e.events & EPOLLERR) { 

      int  error = 0; 
      socklen_t errlen = sizeof(error); 
      auto r1 =getsockopt(c.socket, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen); 
      assert(r1==0); 
      printf("Got EPOLLERR 2 %s\n", strerror(error)); 
     } 


     if(e.events & EPOLLRDHUP || e.events & EPOLLHUP) { 
      if (e.events & EPOLLRDHUP) { 
       printf("got to EPOLLRDHUP\n"); 
      } 
      if (e.events & EPOLLHUP) { 
       printf("got to EPOLLHUP\n"); 
      } 
      //continue; // keeps hitting this for same connections 
      break; 
     } 

     if (e.events & EPOLLIN) { 

      // Does a bunch of reads... 
     } 
    } 
} 

Un seul socket se coincer dans le cas EPOLLRDHUP || EPOLLHUP. Le socket est probablement fermé, quand j'essaie de le fermer ou de faire EPOLL_CTL_DEL j'obtiens un EBADFD. J'ai cru comprendre qu'epoll se débarrasserait automatiquement de toutes les douilles mortes, mais cela ne semble pas être le cas ... des idées? Un autre problème possible est que sur la socket j'utilise recvmsg/sendmsg et j'envoie des descripteurs de fichier entre les processus, sur ces sockets, qui sont des sockets de flux de domaine Unix. J'ai essayé de faire un dernier recvmsg, mais ça échoue aussi ... Des idées?

+0

Je recommande que votre code appelle 'close' avant de terminer le traitement de l'événement' EPOLLHUP'. Notez que 'EPOLLHUP' indique que l'autre partie a fermé la connexion - mais votre code n'a pas encore fermé la connexion. Puisque le 'fd' est toujours ouvert de votre côté,' epoll' continuera de l'interroger. – Myst

+0

@myst Lorsque j'essaie de le fermer, il échoue avec un mauvais descripteur de fichier, dans ce cas. Mais merci pour la recommandation pour le cas général. –

+0

Je suis certain que le client 'fd' (pas le' g.epoll_fd') doit être fermé par votre code afin de libérer ses ressources. Votre code n'est pas un exemple complet, il y a donc une limite à ce que je peux examiner. Je ne suis pas sûr quel appel de fonction provoque le 'EBADFD' ou quelle valeur vous passez à' close'. En fait, je ne sais même pas où vous stockez la valeur 'fd' de l'événement. Vous pouvez le stocker dans l'événement, mais j'utilise parfois l'événement pour stocker un pointeur vers un objet qui contient les données 'fd' ainsi que d'autres informations ... et peut-être que l'erreur se produit parce que vous ne le stockez pas. Je ne peux pas le dire. – Myst

Répondre

0

Pour ma question, la solution était de changer une ligne comme celui-ci:

c.socket = accept(g.server_socket, NULL, NULL); 

à ceci:

c.socket = accept4(g.server_socket, NULL, NULL, SOCK_CLOEXEC); 

Si quelqu'un a ce problème, regardez pour dup() et exec() appels . Un dup() peut provoquer epoll à agir comme s'il n'était pas fermé, même si vous avez déjà fermé le fd que vous avez ajouté à epoll. epoll reconnaîtra seulement qu'il est fermé une fois que toutes les copies de la fd sont fermées. exec() fera essentiellement la même chose qu'un dup() pour chaque fd que vous avez qui n'a pas été créé avec le drapeau SOCK_CLOEXEC ...