LINUX.ORG.RU

[C] poll () Как замаскировать POLLHUP

 


0

0

Здравствуйте!
Такая вот проблема.. запускаю poll с .events = POLLIN для нескольких дескрипторов. 
Пока пишу в пайпы для которых всё это открыто, всё нормально - событие детектится и т.д. 
Но вот когда вдруг один из пайпов закрываю, событие POLLHUP продолжает детектится... 
Как замаскировать это событие? В /usr/include/poll/bits.h сказано:

 /* Event types that can be polled for.  These bits may be set in `events'
   to indicate the interesting event types; they will appear in `revents'
   to indicate the status of the file descriptor.  */
#define POLLIN      0x001       /* There is data to read.  */
#define POLLPRI     0x002       /* There is urgent data to read.  */
#define POLLOUT     0x004       /* Writing now will not block.  */

<...>

/* Event types always implicitly polled for.  These bits need not be set in
   `events', but they will appear in `revents' to indicate the status of
   the file descriptor.  */
#define POLLERR     0x008       /* Error condition.  */
#define POLLHUP     0x010       /* Hung up.  */
#define POLLNVAL    0x020       /* Invalid polling request.  */

И как быть? Переформировывать массив pollfd каждый раз после закрытия одного из потоков? Как-то это неудобно, может есть лучшие варианты?
★★

> событие POLLHUP продолжает детектится

В смысле оно начинает детектится после закрытия канала и детектится постоянно, что, конечно, соответствует описанию в хедере, но нафиг не нужно..

lv ★★
() автор топика
Ответ на: комментарий от lv

В качестве воркэраунда можно, присваивать .fd, на котором замечен POLLHUP скажем STDIN_FILENO и обнулять .events.. но как-то убого это...

(
fds[i].fd = STDIN_FILENO;
fds[i].events = 0;
)

Никто разве не сталкивался? Или все select используют с его FD_CLR?

lv ★★
() автор топика
Ответ на: комментарий от lv

select поддерживается гораздо большим количеством ОС и более переносим.

Если вы закрыли дескриптор, то совершенно правильное действие — перестать его опрашивать, т.е. не передавать в poll.

anonymous
()
Ответ на: комментарий от anonymous

Я тоже склоняюсь к использованию select если с poll не разбирусь. Просто читал в "Разработка приложений в среде linux", что poll более эффеткивен при большом количестве открытых дескрипторов, так как

1. в select передаётся верхняя граница опрашиваемых дескрипторов и ядру приходится проверять все их, чтобы проверить не заинтересовано ли в них приложение.

2. набор файловых дескрипторов передаётся ядру как битовая маска для select и как список для poll. Битовые операции менее эффективны (я ни причём - в книжке так написано :))

3. Ядро перезаписывает fd_set передаваемый в select -> его приходится каждый раз обновлять..

4. максимальный файловый дескриптор для fd_set 1023 -> не масштабируется.. (нету FD_FREE).

Может информация устарела (я в этой книге встречал неточности)..

> Если вы закрыли дескриптор, то совершенно правильное действие — перестать его опрашивать, т.е. не передавать в poll.


То есть нужно формировать новый массив без этого дискриптора??? А почему нету возможности просто замаскировать ненужные события?

lv ★★
() автор топика
Ответ на: комментарий от lv

> То есть нужно формировать новый массив без этого дискриптора??? А почему нету возможности просто замаскировать ненужные события?

Ну как бы что с select, что с poll массив хендлов нужно каждый раз обнулять и заполнять заново. И в таком случае код должен бы выглядить так:

обнулить FD_SET или массив для poll
пройтись по всем клиентам:
....если есть чего написать в хендл - то пишем
....добавляем хендл в массив пола или селекта
вызвать select или poll
пройтись по всем клиентам:
....если клиент выбран select-ом или poll-ом - то прочитать с него данные, если его закрыли - то удалить клиент

тоесть массив всегда перезаполняется

Другое дело - epoll - там как раз хендл добавляется один раз

anonymous
()
Ответ на: комментарий от lv

флаги бывают разные - может есть смысл поиграться с флагами ?
POLLIN - read other than high priority data without blocking
POLLRDNORM - read normal data without blocking
POLLRDBAND - read priority data without blocking
POLLPRI - read high-priority data without blocking
POLLOUT - write normal data without blocking
POLLWRNORM - same as POLLOUT
POLLERR - error occurred on the descriptor
POLLHUP - device has been disconnected
POLLNVAL - file descriptor invalid

вот так например :
void monitorpoll(int fd[], int numfds)  {
   char buf[BUFSIZE];
   int bytesread;
   int i;
   int numnow = 0;
   int numready;
   struct pollfd *pollfd;

   for (i=0; i< numfds; i++)             /* initialize the polling structure */
      if (fd[i] >= 0)
          numnow++;
   if ((pollfd = (void *)calloc(numfds, sizeof(struct pollfd))) == NULL)
      return;
   for (i = 0; i < numfds; i++) {
      (pollfd + i)->fd = *(fd + i);
      (pollfd + i)->events = POLLRDNORM;
   }
   while (numnow > 0) {        /* Continue monitoring until descriptors done */
      numready = poll(pollfd, numfds, -1);
      if ((numready == -1) && (errno == EINTR))
         continue;                /* poll interrupted by a signal, try again */
      else if (numready == -1)            /* real poll error, can't continue */
         break;
      for (i = 0; i < numfds && numready > 0; i++)  {
         if ((pollfd + i)->revents) {
            if ((pollfd + i)->revents & (POLLRDNORM | POLLIN) ) {
               bytesread = r_read(fd[i], buf, BUFSIZE);
               numready--;
               if (bytesread > 0)
                  docommand(buf, bytesread);
               else
                  bytesread = -1;                             /* end of file */
            } else if ((pollfd + i)->revents & (POLLERR | POLLHUP))
               bytesread = -1;
            else                    /* descriptor not involved in this round */
               bytesread = 0;
            if (bytesread == -1) {      /* error occurred, remove descriptor */
               r_close(fd[i]);
               (pollfd + i)->fd = -1;
               numnow--;
            }
         }
      }
   }
   for (i = 0; i < numfds; i++)
       r_close(fd[i]);
   free(pollfd);
}

kto_tama ★★★★★
()

Могу предложить следующее: в .events записывай не POLLIN, а (POLLIN | POLLHUP), а при проверке проверяй флаги не у не .revents, а у (.revents & .events). То есть флаги будут проверяться только запрошенные. Когда дескриптор проверять больше не нужно - обнуляешь events. Если у тебя дескрипторов много и не хочешь чтобы не тратилось время на проверку закрытых - переформировывай массив pollfd с нуля когда ненужными становятся N дескрипторов (например 20).

ИМХО.

Deleted
()
Ответ на: комментарий от kto_tama

> флаги бывают разные - может есть смысл поиграться с флагами ?
Смысла нет - в хедере явно описано что как работает.

Всем спасибо за ответы. Если нет другого способа, кроме как постоянная перекройка массива, значит так тому и быть. Просто хотел этого избежать.. :)

lv ★★
() автор топика
Ответ на: комментарий от Deleted

> Могу предложить следующее: в .events записывай не POLLIN, а (POLLIN | POLLHUP), а при проверке проверяй флаги не у не .revents, а у (.revents & .events). То есть флаги будут проверяться только запрошенные. Когда дескриптор проверять больше не нужно - обнуляешь events. Если у тебя дескрипторов много и не хочешь чтобы не тратилось время на проверку закрытых - переформировывай массив pollfd с нуля когда ненужными становятся N дескрипторов (например 20).

Фигня получится, так как закрытый дескриптор будет приводить к постоянной генерации события на poll. Оно конечно при проверке будет давиться, но не приведёт ли это к холостой загрузке системы?

lv ★★
() автор топика
Ответ на: комментарий от lv

Или может я не прав, и poll() и так постоянно опрашивает эти дескрипторы? По принципу каллбаков, когда ядро само будит процесс, если на файле появилось событие, возможно только epoll организован? Или как там всё это работает?

lv ★★
() автор топика
Ответ на: комментарий от lv

>> Оно конечно при проверке будет давиться, но не приведёт ли это к холостой загрузке системы?

Дополнительная нагрузка на систему будет, но ИМХО очень маленькая. Если хочешь от неё избавиться - всётаки придётся переформировывать массив pollfd. Хотя что там переформировывать то? Просто пройтись циклом по всем элементам после ненужного дескриптора и "сдвинуть" поля .fd в массиве влево на один елемент.

Deleted
()
Ответ на: комментарий от Deleted

> Просто пройтись циклом по всем элементам после ненужного дескриптора и "сдвинуть" поля .fd в массиве влево на один елемент.

Ну да, ну да... самый, видимо, разумный вариант в такой ситуации. А есть какие-нибудь идеи, почему так сделано, что POLLHUP, POLLERR и POLLNVAL не маскируются? Ну можно было бы сделать, чтобы они явно указывались в .events для детектинга, а если не указаны, то и poll бы на них не реагировал.. Видимо я как-то не до конца понимаю замысел дизайнера..

lv ★★
() автор топика
Ответ на: комментарий от anonymous

> Если дескрипторов много, то связанный список выгоднее.

И как же его в poll() передавать? poll() ведь принимает указатель на массив и размер этого массива..

lv ★★
() автор топика

сколько дескрипторов? если меньше милиона то беспокоиться о перекройке массива глупость, как говориться преждевременная оптимизация зло, и тем более возможно я чего-то не понимаю но ведь можно поменять последний элемент массива с выбывшем и все копейки процессорного времени

anonymous
()
Ответ на: комментарий от anonymous

>> и тем более возможно я чего-то не понимаю но ведь можно поменять последний элемент массива с выбывшем и все копейки процессорного времени

Бггг, это просто гениально =). А я туплю, ибо час ночи...

Deleted
()
Ответ на: комментарий от lv

> Если нет другого способа, кроме как постоянная перекройка массива

epoll

anonymous
()
Ответ на: комментарий от Deleted

> Бггг, это просто гениально =). А я туплю, ибо час ночи...

Ага, :)) аналогично :)

lv ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.