Обработчики сигналов не являются магией.Они вызываются в режиме пользователя, поэтому они должны вызываться в коде пользователя.Но они могут быть обнаружены только в режиме ядра, поэтому ядро передает сигнал процессу и каким-либо образом указывает, что процесс должен выполняться в пользовательском режиме, когда вызывается обработчик сигнала.
Это происходит только тогда, когдапроцесс выполняет системный вызов или обычно, когда ядро выгружает процесс, потому что он слишком долго работал.Поскольку код должен выполняться в пользовательском режиме, разработчики UNIX (и, боюсь, это преобладало до сих пор), вызов обработчиков сигналов происходит именно тогда, когда ядро собирается вернуться к пользовательскому процессу (механизм состоит изпри манипулировании пользовательским стеком для перехода к обработчику сигналов при возврате из системного вызова, и позволить такому искалеченному стеку возвращаться к прерванному коду, как если бы прерывание было истинным аппаратным прерыванием.возможность запуска в режиме ядра.
Когда процесс останавливается при системном вызове, механизм прост, так как пользовательский процесс не выполняет пользовательский код, и обработчик сигнала будет вызываться очень специфичноточка, после возврата syscall (таким образом, место фактически находится в точке кода сразу после системного вызова --- который возвращает -1
с errno
, установленным на EINTR
, но вы действительно можете проверить это только после обработчик сигнала уже был вызван), ноn процесс вытеснен, есть проблема, что процесс может быть где угодно в его коде.Упомянутое выше искажение стека должно иметь дело с этим и быть готовым восстановить полное состояние процессора (как это происходит с возвратом из аппаратного прерывания), чтобы иметь возможность выполнить обработчик сигнала в любой точке пользовательского кода и выйтивсе правильно.С этим проблем нет, так как ядро сохранило его, когда прервал процесс.Единственное отличие состоит в том, что полное восстановление состояния процессора откладывается до тех пор, пока не будет выполнен обработчик сигнала, после возврата в пользовательский режим.
Код для управления обработчиком сигналов обычно устанавливается ядром на карту памяти пользовательского режима.(в системах BSD это происходит в верхней части стека потоков основного процесса, прежде чем задавать параметры среды и параметры exec(2)
args и argv
, argc
.) Но это может быть где угодно в виртуальном пространстве программы.
Ваш случай здесь - чистое выполнение в пользовательском коде, поэтому, пока ядро не выгрузит процесс, он не получит сигнал.Это может произойти где-нибудь в цикле, когда прерывание по таймеру останавливает процесс и процесс перепланируется снова, непосредственно перед возвратом в пользовательский режим, стек искажается, чтобы вызвать переход к диспетчеру обработчика сигналов, происходит переключение в пользовательский режим., это заставляет программу переходить к диспетчеру обработчиков сигналов, она вызывает ваш обработчик сигналов, затем диспетчер обработчиков сигналов восстанавливает состояние полного процессора и возвращается в то место, где ядро прервало процесс, как если бы прерывание вызвало аппаратное прерывание.