Обработка сигналов в отладке и в свободном исполнении - PullRequest
1 голос
/ 11 февраля 2020

Я должен обработать SIGINT и SIGTERM в моей программе, которая использует Boost.Asio. Для этого я использую boost::asio::signal_set::async_wait().

Проблема в том, что обработчик сигнала получает управление только тогда, когда я просто запускаю приложение, а не при отладке.

Вот некоторый код:

Proxy::Proxy():
    signals_(ioContext_, SIGINT, SIGTERM)
{
    signals_.async_wait(
        [this](const boost::system::error_code& error, int)
        {
            if (!error)
                ioContext_.stop();
        }
    );
}

Proxy::run()
{
    ioContext_.run();
}

Когда мы run() Proxy, ioContext_ начинают обрабатывать события. Если мы просто запустим программу и введем Ctrl+C в терминале, обработчик сигнала (то есть лямбда) остановит ioContext_ (как мы и ожидаем), и io_context::run вернет управление. Но в режиме отладки программа реагирует на Ctrl+C, но выполнение останавливается где-то на epoll_wait(). Если мы продолжим выполнение, оно будет зависать где-то в epoll_wait() и т. Д.

Вот трассировка стека, где останавливается выполнение:

epoll_wait
boost::asio::detail::epoll_reactor::run
boost::asio::detail::scheduler::do_one_run
boost::asio::detail::scheduler::run
boost::asio::io_context::run
Proxy::run
main

Почему это происходит в отладке режим но не иначе?

1 Ответ

4 голосов
/ 11 февраля 2020

Проблема здесь в том, что GDB использует SIGINT в качестве механизма прерывания программы и позволяет вам начать отладку.

(gdb) info signals SIGINT
Signal        Stop      Print   Pass to program Description
SIGINT        Yes       Yes     No              Interrupt

Это говорит о том, что GDB не должен передавать SIGINT s в программа, но следует использовать это, чтобы остановить программу и вывести вас в приглашение GDB. Самый простой механизм отправки его в вашу программу - это послать сигнал от GDB в этот момент:

(gdb) signal SIGINT

Теперь ваша программа должна продолжить работу, как ожидалось.


В зависимости от того, как часто вы делаете это, ввод signal SIGINT может быть неудобным. К счастью, GDB позволяет вам изменить способ обработки сигналов . Вы хотите, чтобы SIGINT не останавливал программу (перетянул вас в приглашение GDB) и передавал ее программе.

(gdb) handle SIGINT nostop pass
SIGINT is used by the debugger.
Are you sure you want to change it? (y or n) y
Signal        Stop      Print   Pass to program Description
SIGINT        No        Yes     Yes             Interrupt

Теперь мы находимся в стране "слегка нежелательной", поскольку больше не может использовать Ctrl + C, чтобы перейти в нашу подсказку GDB. Вам придется полагаться на предустановленные точки останова и другие механизмы.

Если вы хотите получить более продвинутый уровень, вы можете использовать catch и commands, чтобы определить источник SIGINT (взято из Отладка программы, которая использует SIGINT с gdb ):

catch signal SIGINT
commands
  if $_siginfo._sifields._kill.si_pid == 0
    print "Received SIGINT from tty"
  else
    printf "Received SIGINT from %d; continuing\n", $_siginfo._sifields._kill.si_pid
    signal SIGINT
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...