Модераторы: xvr
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Обработка сигналов в Bash 
:(
    Опции темы
savigm
  Дата 26.3.2009, 19:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 88
Регистрация: 15.12.2008
Где: г. Зеленоград

Репутация: нет
Всего: нет



Добрый день.
Есть скрипт на bash запускающий программу, не соодержащую обработчика сигналов. По запуску скрипта, во время выполнения программы, если нажать [CTRL]+[C] - на экран вылезет ^C. Одно из двух - либо bash отображает введенный символ, либо ядро обрабатывая сигнал и выдает на терминал ^C. Поясните поподробней от кого идет выдача и как этого избажать(перенаправление вввода-вывода не помогает).
PM MAIL ICQ   Вверх
MAKCim
Дата 26.3.2009, 23:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



я так понимаю речь идет про GUI эмулятор терминала типа gnome-terminal и Konsole

обычно с GUI эмуляторами терминалов связываются программы-интерпретаторы (bash, csh, zsh и т. д)
говоря простым языком это то, что мы прописываем в конфиге (или в другом месте) GUI программы и что запускается при ее старте

если углубиться в детали, то происходит следующее
1. при запуске GUI эмулятора он через open() открывает /dev/ptmx
реализация обработчика open для /dev/ptmx создает псевдотерминальное устройство, состоящее из master и slave компонентов
доступ к master компоненту имеет только процесс GUI эмулятора (open() возвращает ему соответствующий дескриптор)
slave компонент доступен любому процессу через виртуальную ФС /dev/pts (в процессе работы обработчика open slave компонент отображается на /dev/pts в виде файла символьного устройства 0, 1, 2, ..., который можно открыть)
2. GUI эмулятор порождает процесс и запускает в нем соответствующий ему интерпретатор через execve()
перед вызовом execve() он перенаправляет стандартный ввод-вывод порожденного процесса на /dev/pts/X, где X - символьное устройство, соответствующее slave компоненту псевдотерминального устройства
все, связь готова
3. GUI эмулятор связан через gtk[+]/qt с Xlib API, через который он взаимодействует с X сервером и в частности получает события от клавиатуры
при наборе текста (это могут быть скан-коды или что-то другое)
на этом уровне различные комбинации типа ^C представляют собой просто последовательность байт
4. вся последовательность байт as is записывается в master компонент через write() на дескрипторе

вот тут начинаетс шаманство ;)
из буфера master компонента последовательность байт передается в slave компонент, где идет ее преобразование в соответствие с настройками slave компонента
настроить можно через ioctl или tc* обертки на дескрипторе, полученном через open() на /dev/pts/X
здесь как раз можно связать управляющую комбинацию ^C и генерацию сигнала
т. е slave компонент при парсинге последовательности байт может сгенерировать сигнал для всех  процессов из foreground группы, которые используют /dev/pts/X в виде дескриптора

bash всегда перехватывает SIGINT (маппинг ^C) и записывает символьную последовательность "^C" на стандартный поток вывода, который, как я отмечал выше, связан со slave компонентом. Эта последовательность байт без изменений копируется в приемный буфер master компонента
дальше GUI эмулятор может прочесть эти данные через read() на своем дескрипторе и вывести их через Xlib API на экран


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
savigm
Дата 27.3.2009, 01:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 88
Регистрация: 15.12.2008
Где: г. Зеленоград

Репутация: нет
Всего: нет



Ok, тогда как обьяснить аналогичное явление в виртуальной консоли (не терминале):
в login (это еще не bash) нажатие [Ctrl]+[C] также приводит к отображению ^C?
Во время работы программы ввод-вывод если я не ошибаюсь идет уже не с bash, а с программой.
Как все-таки этого избежать? Есть прогамка с обработчиком сигнала SIGINT, так она нормально завершается ничего не отображая. Получается сей эффект проявляется только если в программе не установлен обработчик сигнала? Кроме того: если посылать kill -2 <PID>, никакого ^C нет. Т.е. это следствие нажатия клавиш, а не сигнала как такового, однако наличие обработчика решает проблему.

Это сообщение отредактировал(а) savigm - 27.3.2009, 01:50
PM MAIL ICQ   Вверх
MAKCim
Дата 27.3.2009, 09:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



Цитата(savigm @  27.3.2009,  01:37 Найти цитируемый пост)
Во время работы программы ввод-вывод если я не ошибаюсь идет уже не с bash, а с программой.

я же специально написал

Цитата(MAKCim @  26.3.2009,  23:20 Найти цитируемый пост)
т. е slave компонент при парсинге последовательности байт может сгенерировать сигнал для всех  процессов из foreground группы, которые используют /dev/pts/X в виде дескриптора

замени /dev/pts/X на /dev/ttyX и получишт тот же эффект для login

Добавлено через 10 минут и 20 секунд
Цитата(savigm @  27.3.2009,  01:37 Найти цитируемый пост)
Как все-таки этого избежать?

посмотри опции stty


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
savigm
Дата 27.3.2009, 13:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 88
Регистрация: 15.12.2008
Где: г. Зеленоград

Репутация: нет
Всего: нет



Цитата(MAKCim @  26.3.2009,  23:20 Найти цитируемый пост)
вот тут начинаетс шаманство ;)
из буфера master компонента последовательность байт передается в slave компонент, где идет ее преобразование в соответствие с настройками slave компонента
настроить можно через ioctl или tc* обертки на дескрипторе, полученном через open() на /dev/pts/X
здесь как раз можно связать управляющую комбинацию ^C и генерацию сигнала
т. е slave компонент при парсинге последовательности байт может сгенерировать сигнал для всех  процессов из foreground группы, которые используют /dev/pts/X в виде дескриптора

bash всегда перехватывает SIGINT (маппинг ^C) и записывает символьную последовательность "^C" на стандартный поток вывода, который, как я отмечал выше, связан со slave компонентом.


Slave компонент насколько я понимаю связан с bash?

Если в терминале у меня запущена программа весь ввод и вывод идет на нее по схеме Клавиатура/Монитор<->Терминал<->Bash<->Программа? Т.е. весь клавиатурный ввод серва парсится bash'ом, потом отправляется на /dev/ptsx?

Что значит "для всех  процессов из foreground группы", разве foreground - это не единственная программа запущенная в bash и занимающая ввод-вывод консоли/терминала?

Интересный факт: в интерпретаторе bash если нажать [Ctrl]+[C], он перехватывает сигнал и на терминал выводится символ новой строки вместо ^C. Вот код из исходников bash - файл sig.c:
Код

#if defined (READLINE)
  if (interactive)
    bashline_reinitialize ();
#endif /* READLINE */

#if defined (PROCESS_SUBSTITUTION)
  unlink_fifo_list ();
#endif /* PROCESS_SUBSTITUTION */

  run_unwind_protects ();
  loop_level = continuing = breaking = 0;
  return_catch_flag = 0;

  if (interactive && print_newline)
    {
      fflush (stdout);
      fprintf (stderr, "\n");
      fflush (stderr);
    }

  /* An interrupted `wait' command in a script does not exit the script. */
  if (interactive || (interactive_shell && !shell_initialized) ||
      (print_newline && signal_is_trapped (SIGINT)))
    jump_to_top_level (DISCARD);
  else
    jump_to_top_level (EXITPROG);


Вот еще интересный кусочек из исходников bash - файл jobs.c, правда относящийся к job control(в комментарии ясно написано что выводом ^C занимается обработчик ядра):
Код

          /* If job control is enabled, the job was started with job
             control, the job was the foreground job, and it was killed
             by SIGINT, then print a newline to compensate for the kernel
             printing the ^C without a trailing newline. */
          if (job_control && IS_JOBCONTROL (job) && IS_FOREGROUND (job) &&
                WIFSIGNALED (s) && WTERMSIG (s) == SIGINT)
            {
              /* If SIGINT is not trapped and the shell is in a for, while,
                 or until loop, act as if the shell received SIGINT as
                 well, so the loop can be broken.  This doesn't call the
                 SIGINT signal handler; maybe it should. */
              if (signal_is_trapped (SIGINT) == 0 && loop_level)
                  ADDINTERRUPT;
              else
                {
                  putchar ('\n');
                  fflush (stdout);
                }
            }


Это сообщение отредактировал(а) savigm - 27.3.2009, 13:12
PM MAIL ICQ   Вверх
MAKCim
Дата 27.3.2009, 15:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



Цитата(savigm @  27.3.2009,  13:06 Найти цитируемый пост)
Клавиатура/Монитор<->Терминал<->Bash<->Программа?

bash лишний в цепочке
и bash, и программа используют один и тот же /dev/pts/X

а вообще меня самого заинтересовало
как-нибудь на досуге разрулю этот вопрос


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
savigm
Дата 28.3.2009, 01:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 88
Регистрация: 15.12.2008
Где: г. Зеленоград

Репутация: нет
Всего: нет



stty -echoctl - действительно помогает, но я решил проблему иным путем: т.к. моя программа не использует ввод, то я просто отрубил ECHO в начале программы и включил в конце, но это все work around, суть вопроса по прежнему не ясна. Насколько я понимаю все дело в настройках терминала, т.е. по идее на терминале должно отобразится что-то типа ^[[ и т.п. а терминал преобразует это в ^C ^Q и т.п.
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Программирование под Unix/Linux"
xvr
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой "Код".
  • Вопросы мобильной разработки тут
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, xvr.

 
 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Программирование под Unix/Linux | Следующая тема »


 




[ Время генерации скрипта: 0.0491 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.