Почему strace и ltrace вызывают возникновение EINTR?

Почему strace и ltrace вызывают возникновение EINTR?

Рассмотрим эту программу:

#include <stdio.h>
#include <sys/epoll.h>

int main(void) {
       int epfd = epoll_create1(0);
       struct epoll_event event;
       event.events = EPOLLIN;
       event.data.fd = 0;
       epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &event);
       epoll_wait(epfd, &event, 1, -1);
       perror("epoll_wait");
       return 0;
}

Когда я запускаю эту программу отдельно, изменение размера терминала (тем самым генерируя SIGWINCH) ничего не делает с ней, и она продолжает ждать ввода на stdin. Когда я запускаю ее внутри strace или ltrace, SIGWINCH приводит к ошибке epoll_wait с EINTR. Я понимаю EINTR так, что он генерируется только в том случае, если сигнал вызывает обработчик сигнала в вашем коде, но у меня ни один из них не зарегистрирован. Я думал, что strace или ltrace могли установить его для меня, поэтому я попробовал явно установить его в SIG_IGN, но это все равно не остановило EINTR. Почему это происходит?

решение1

Они используютptrace(2), чьи комментарии к странице руководства

Во время отслеживания трассируемый объект будет останавливаться каждый раз при получении сигнала,даже если сигнал игнорируется. (Исключением является SIGKILL, что имеет свой обычный эффект.) Трейсер будет уведомлен при следующем вызовеwaitpid(2)(или один из связанных системных вызовов "wait"); этот вызов вернет значение статуса, содержащее информацию, указывающую причину остановки трассируемой. Пока трассируемая линия остановлена, трассировщик может использовать различные запросы ptrace для проверки и изменения трассируемой линии. Затем трассировщик заставляет трассируемую линию продолжить работу, опционально игнорируя доставленный сигнал (или даже доставляя вместо этого другой сигнал).

и позже:

Обратите внимание, что подавленный сигнал все еще приводит к преждевременному возврату системных вызовов. В этом случае системные вызовы будут перезапущены: трассировщик будет наблюдать, как трассируемый повторно выполняет прерванный системный вызов (или restart_syscall(2) системный вызов для нескольких системных вызовов, которые используют другой механизм для перезапуска), если трассировщик использует PTRACE_SYSCALL. Даже системные вызовы (такие какpoll(2)) которые не подлежат перезапуску после сигнала, перезапускаются после подавления сигнала;Однако существуют ошибки ядра, которые приводят к сбою некоторых системных вызовов с EINTR, даже если в трассируемую цепочку не вводится наблюдаемый сигнал..

По умолчанию,SIGWINCHигнорируется, но звучит достаточно epollпохоже, pollчтобы быть EINTRвидимым для вызывающего абонента (даже после перезапуска).

Связанный контент