Почему Linux всегда выводит "^C " при нажатии Ctrl+C?

Я изучал сигналы в Linux. И я сделал тестовую программу для захвата SIGINT.

#include <unistd.h>
#include <signal.h>
#include <iostream>
void signal_handler(int signal_no);
int main() {
  signal(SIGINT, signal_handler);
  for (int i = 0; i < 10; ++i) {
  std::cout << "I'm sleeping..." << std::endl;
  unsigned int one_ms = 1000;
  usleep(200* one_ms);
  }
  return 0;
}
void signal_handler(int signal_no) {
  if (signal_no == SIGINT)
    std::cout << "Oops, you pressed Ctrl+C!n";
  return;
}

пока вывод выглядит так:

I'm sleeping...
I'm sleeping...
^COops, you pressed Ctrl+C!
I'm sleeping...
I'm sleeping...
^COops, you pressed Ctrl+C!
I'm sleeping...
^COops, you pressed Ctrl+C!
I'm sleeping...
^COops, you pressed Ctrl+C!
I'm sleeping...
^COops, you pressed Ctrl+C!
I'm sleeping...
I'm sleeping...
I'm sleeping...

Я понимаю, что при нажатии Ctrl+C процессы в группе процессов переднего плана получают SIGINT(если ни один процесс не игнорирует его).

Итак, оболочка (bash)и экземпляр вышеуказанной программы получили сигнал? Где "^C "перед каждым "ой" приходит от?

ОС-CentOS, а оболочка-bash.

2 ответов


это терминал (драйвер), который перехватывает ^C и переводит его в сигнал, отправленный в прикрепленный процесс (который является оболочкой) stty intr ^B проинструктирует водителя терминала перехватить a ^B вместо этого. Это также драйвер терминала, который повторяет ^C обратно к терминалу.

оболочка-это просто процесс, который находится на другом конце линии, и получает его stdin от вашего терминала через драйвер терминала (например, /dev / ttyX), и это stdout (и stderr) также прикрепленный к тому же tty.

обратите внимание, что (если Эхо включено) терминал посылает нажатия клавиш в и процесс (группа) и обратно к терминалу. Команда stty-это просто оболочка вокруг ioctl () для драйвера tty для процессов "управления" tty.

Update: чтобы продемонстрировать, что оболочка не участвует, я создал следующую небольшую программу. Он должен быть выполнен родительской оболочкой через exec ./a.out (появляется интерактивная оболочка fork дочерняя оболочка, так или иначе) программа устанавливает ключ, который генерирует SIGINTR в ^B, отключает эхо и ждет ввода от stdin.

#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

int thesignum = 0;
void handler(int signum);

void handler(int signum)
{ thesignum = signum;}

#define THE_KEY 2 /* ^B */

int main(void)
{
int rc;
struct termios mytermios;

rc = tcgetattr(0 , &mytermios);
printf("tcgetattr=%d\n", rc );

mytermios.c_cc[VINTR] = THE_KEY; /* set intr to ^B */
mytermios.c_lflag &= ~ECHO ; /* Dont echo */
rc = tcsetattr(0 , TCSANOW, &mytermios);
printf("tcsetattr(intr,%d) =%d\n", THE_KEY, rc );

printf("Setting handler()\n" );
signal(SIGINT, handler);

printf("entering pause()\n... type something followed by ^%c\n", '@'+THE_KEY );
rc = pause();
printf("Rc=%d: %d(%s), signum=%d\n", rc, errno , strerror(errno), thesignum );

// mytermios.c_cc[VINTR] = 3; /* reset intr to ^C */
mytermios.c_lflag |= ECHO ; /* Do echo */
rc = tcsetattr(0 , TCSANOW, &mytermios);
printf("tcsetattr(intr,%d) =%d\n", THE_KEY, rc );

return 0;
}

intr.sh:

#!/bin/sh
echo $$
exec ./a.out
echo I am back.

оболочка повторяет все, что вы печатаете, когда вы типа ^C, Это тоже получает эхо (и в вашем случае перехвачено вашим обработчиком сигнала). Команда stty -echo может быть или не быть полезным для вас в зависимости от ваших потребностей/ограничений, см. man page для stty для получения дополнительной информации.

конечно, гораздо больше происходит на более низком уровне,в любое время вы общаться с системой через драйверы периферийных устройств (например, драйвер клавиатуры, который вы используете для генерируйте сигнал ^C, и драйвер терминала, который отображает все) участвуют. Вы можете копать еще глубже на уровне ассемблера / машинного языка, регистров, таблиц поиска и т. д. Если вы хотите получить более подробный, углубленный уровень понимания, книги ниже-хорошее место для начала:

дизайн ОС Unix является хорошей ссылкой для такого рода вещей. Еще две классические ссылки:Среда Программирования Unix и передовая Программирование в среде UNIX

хорошее резюме здесь, в этом вопросе SO как Ctrl-C завершает дочерний процесс?

"когда вы запускаете программу, например find оболочка:

  • сама вилка раковины
  • и для ребенка установите обработку сигнала по умолчанию
  • замените ребенка данной командой (например, с помощью find)
  • когда вы нажимаете CTRL - C, родительская оболочка обрабатывает это сигнал, но ребенок получит его - с действием по умолчанию-прекратить. (ребенок также может реализовать обработку сигналов)"