Прерывание (n)проклятия getch на входящем сигнале

одна из моих программ использует ncurses для рисования небольшого tui. Одна из моих целей-сделать его довольно портативным для других реализаций проклятий. Это означает, что я хочу поймать SIGWINCH, выпущенный эмулятором терминала, на операции изменения размера и обновить мой tui, чтобы придерживаться измененной геометрии (и не зависеть от средств изменения размера ncurses). Поскольку POSIX (насколько я знаю) разрешает доступ только к sig_atomic_t переменные в обработчике сигнала, я установил один в другое состояние. В основной цикл, моя программа проверяет, изменилось ли состояние и обновляет tui, если это необходимо.

но теперь у меня проблема, что моя программа зависает в getch, когда поступает сигнал. В документации ncurses указано, что обработанные сигналы никогда не прерывают его. Это означает, что размер tui не обновляется до нажатия клавиши ввода.

есть ли какой-либо портативный способ прервать getch? Мой текущий подход -ungetch фиктивный ключ в обработчике сигнала, но я не конечно, если это разрешено. На самом деле я не смог найти никакой документации относительно того, может ли функция curses использоваться в обработчике сигнала или нет. Есть идеи, как правильно решить этот вопрос?

в отношении

4 ответов


из документации FreeBSD getch, прерывание getch зависит от используемой системы:

программисты, обеспокоенные переносимостью, должны быть готовы к из двух случаев: (a) прием сигнала не прерывает getch; (b) сигнал получение прерывает getch и заставляет его возвращать ERR с набором errno с ошибкой eintr. В рамках реализации ncurses обрабатываются сигналы никогда не прерывай гетча.

Я думаю, что вы должны рассмотрим использование потоков, один поток, заряженный для использования getch () и передачи данных в основной поток, который их обрабатывает. Вы сможете убить поток, который использует getch() при отправке сигнала SIGWINCH, и перезапустить его, если хотите. Но убийство потока, который использует getch (), может быть бесполезным, потому что основной поток не блокируется getch ().

вы можете получить неблокирующие входы без ncurses, как описано на этом страница. Но вы можете использовать read(STDIN_FILENO, &c, sizeof(char)) вместо ввода из fgetc() в Примере, потому что read возвращает значение


одно руководство вы должны следовать, чтобы сделать как можно меньше в процедурах прерывания. Если вы делаете что-то большее, чем установка флага, именно тогда вы должны подумать о переосмыслении своего решения.

на


прошло некоторое время, но я уверен, что вы можете longjmp из обработчика. Не уверен, как это будет работать с ncurses.

http://www.csl.mtu.edu/cs4411.ck/www/NOTES/non-local-goto/sig-1.html

EDIT: У МЕНЯ ЕСТЬ НОВЫЙ ОТВЕТ ******************************

Я думаю, что неблокирующее чтение - это ваш билет, следующее отлично работает для меня. Кроме того, в моей реализации я получаю целочисленное значение "410", когда происходит событие изменения размера, но эта версия не использует этот флаг resize. Попробовать?

У меня есть тайм-аут, установленный на 10 мс, это вернет ERR вместо символа 100 раз в секунду, когда ничего не происходит и сразу же ловит изменения размера. 100 раз в секунду-это ничто... на моем нижнем конце машины 8 минут этого даже не регистрируется в команде cput 'time' (используется 0.000 user и sys).

#include <curses.h>
#include <signal.h>

int resized = 0;

void handle_resize(int sig)
{
  resized = 1;
}

int main(int argc, char * argv[])
{
   WINDOW * w;
   w = initscr();
   timeout(10); // getch returns ERR if no data within X ms
   cbreak();
   noecho();

   signal(SIGWINCH, handle_resize);

   int c, i;

   while (1) {
      c = getch();

      if(resized) {
         resized = 0;
         endwin();
         refresh();
         clear();

         mvprintw(0, 0, "COLS = %d, LINES = %d", COLS, LINES);
         for (i = 0; i < COLS; i++)
            mvaddch(1, i, '*');

         refresh();
      } 

      if (c != ERR) {
         mvprintw(2, 0, "Got character %c (%d)\n", c, c);
      }
  }//while 1

   endwin();
   return 0;
}

соглашаясь с @Emilien, это, вероятно, дубликат ncurses-изменение размера Глюк.

однако OP никогда не показывал рабочий код для демонстрации ситуации.

за исключением OpenBSD, где функция была отключена (до ), getch должен вернуть KEY_RESIZE on SIGWINCH. Данная причина отключения была связана с заботой о sig_atomic_t это было адресовано в 2007 (см. ncurses OpenBSD не имеет USE_SIGWINCH например).

кроме этого,обычно причина не получить KEY_RESIZE Если установить SIGWINCH обработчик (который предотвращает запуск одного из ncurses). Вот в чем была проблема в ncurses-изменение размера Глюк (к которому ни один из предложенных ответов не обращался).

решение endwin / refresh хорошо известно (см. обработка SIGWINCH (изменение размера событий), в ncurses FAQ с 1997 года). The resizeterm ручная страница суммирует это в своем разделе переносимости. Если вы прочтете это, вы поймете, что

  • если KEY_RESIZE определено, тогда реализация поддерживает SIGWINCH обработчик более / менее совместим с ncurses и
  • если это не так, то решение endwin / refresh-это все, что есть доступный.

комментарии цитата из библиотеки по curs_getch (3x) ручная страница в принятом ответе, кстати, не относится к блокировке SIGWINCH, но к обходному пути в библиотеке, чтобы предотвратить возврат ошибки в приложение, когда сигнал прерывает чтение. Если Вы читаете весь раздел переносимости этой страницы руководства, это должно быть очевидно.

Emacs, конечно, использует только termcap интерфейс на ncurses, а не проклятия. Поэтому комментарии о том, как он обрабатывает SIGWINCH не имеют никакого отношения.