netlib.narod.ru | < Назад | Оглавление | Далее > |
С точки зрения пользователя отправка сигналов предельно проста: стоит лишь инициировать системный вызов kill и передать ему идентификатор процесса и собственно сигнал. Однако, сама реализация оказывается не настоль простой.
28768: sys_kill представляет собой обманчиво простую реализацию системного вызова kill; реальная работа сокрыта в kill_somethmg_info, к которому вы вернемся несколько позже. sys_kill принимает следующие аргументы: отправляемый сигнал sig и идентификатор адресата, которому предназначается сигнал, pid. Как вскоре будет показано, pid может и не быть идентификатором процесса. (PID и другие базовые концепции, связанные с процессами, рассматриваются в главе 7.)
28770: Объявление и заполнение структуры struct siginfo на основе информации, переданной в sys_kill. В частности, поле si_code устанавливается в SI_USER (поскольку этот системный вызов может выполнить только пользовательская программа; само ядро этого никогда не делает, предпочитая пользоваться низкоуровневыми функциями).
28778: Передает подготовленную информацию в функцию kill_something_info, которая и делает всю работу.
28484: Аргументы этой функции такие же, как и для sys_kill плюс указатель на структуру struct siginfo.
28487: Если pid равен 0, это значит, что текущий процесс желает отправить сигнал во всю свою группу процессов; это достигается обращением к kill_pg_info (строка 28408).
28489: Если pid равен –1, это значит, что сигнал передается (почти) каждому процессу в системе. Как это делается — описано ниже.
28494: Использование макроса for_each_task (определенного в строке 16898; см. главу 7) для выполнения итерации по списку всех существующих процессов в системе.
28496: Если данный процесс не является ожидающим (или процессом init), отправить сигнал с использованием send_sig_info (строка 28218). При каждом нахождении подходящей задачи увеличивается count, хотя функцию kill_something_info мало интересует подобный подсчет. Если попытка отправки сигнала успехом не увенчалась, запоминается состояние ошибки, таким образом, kill_something_info может вернуть соответствующий код ошибки в строке 28503; если имело место более одного сбоя, возвращается код ошибки только для последнего из них.
28503: Если найден хотя бы один подходящий кандидат, kill_somcthing_info возвращает 0 в случае успеха либо код последней возникшей ошибки в случае неудачи. Если ни одного кандидата не нашлось, возвращается код ошибки ESRCH.
28504: Отрицательные значения pid, отличные от –1, определяют группу процессов, которые должны получить сигнал; при этом модуль pid представляет собой номер группы. Как и ранее, для отправки сигнала используется kill_pg_info.
28506: Здесь учитываются другие возможности, когда pid положительный. В данном случае передаваемое значение представляет собой PID для одиночного процесса, которому должен отправляться сигнал. Для отправки выполняется обращение к kill_proc_info (строка 28463).
28408: Эта функция отправляет сигнал и структуру struct siginfo каждому процессу в группе. Тело функции подобно некоторому коду из kill_something_info, которая рассматривалась ранее.
28417: Итерация по всем процессам системы.
28418: Если текущий процесс принадлежит требуемой группе, отправить сигнал.
28427: В случае успешной отправки сигнала retval устанавливается в 0 и в строке 28430 возвращается. Если сигнал не может быть отправлен ни одному процессу либо заданная группа не содержит ни одного процесса, в строке 28415 значение retval устанавливается равным –ESRCH. Если же kill_pg_info предпринимала попытки отправить сигнал одному и более процессов, но каждый раз терпела неудачу, retval получает значение последней ошибки из send_sig_info. Это несколько отличается от случая kill_something_info, при котором состояние ошибки возвращалось, когда все доставки сигналов завершались сбоями. Здесь, в функции kill_pg_info, успех возвращается даже при условии удачной доставки сигнала хотя бы одному процессу.
28430: Значение retval устанавливается либо как описывалось ранее, либо в –EINVAL (строка 28410), если был передан неверный номер группы процессов.
28463: kill_proc_info — это исключительно простая функция, которая отправляет сигнал и структуру struct siginfo одному процессу, заданному идентификатором PID.
28469: Поиск процесса по переданному PID; функция fmd_task_by_pid (строка 16570) вернет либо соответствующий указатель, если процесс найден, либо NULL в противном случае.
28472: Если совпадение найдено, сигнал отправляется требуемому процессу при помощи send_sig_info.
28474: Возврат состояния ошибки, которое равно либо –ESRCH (строка 28470), если процесс не найден, либо, в противном случае, значению возврата из send_sig_info.
28218: Функция send_sig_info является несомненно основополагающей, так сказать «рабочей лошадкой», для множества функций, рассмотренных до сего момента. Эти функции каким-то образом отыскивали необходимый процесс (или процессы), а всю реальную работу перекладывали на плечи send_sig_info. Сейчас мы рассмотрим, что же здесь на самом деле происходит. send_sig_info отправляет сигнал sig, используя дополнительную информацию, на которую указывает info (кстати, может быть и NULL), процессу, заданному указателем t (предполагается, что t никогда не может быть NULL; об этом должны позаботиться перед вызовом).
28229: Проверка значения sig на предмет попадания в диапазон допустимых значений. Следует заметить, что существующая проверка:
sig > _NSIG
отличается от той, что можно было ожидать:
sig >= _NSIG
Все дело в том, что нумерация сигналов начинается с 1, а не с 0. Следовательно, допустимое количество сигналов _NSIG может рассматриваться и как допустимый номер сигнала.
28233: Еще одна разумная проверка готовности. Главная идея заключается в том, чтобы убедиться в законности отправки сигналов. Ядро имеет право отправлять сигналы любому процессу, в то время как пользователи, отличные от привилегированного (root), не могут посылать сигналы процессам, принадлежащим другим пользователям, за исключением покрытого мраком случая с привлечением SIGCONT. В общем, длинное условие в if означает следующее:
Из рассмотренного выше условия можно сделать два заключения. Во-первых, если info равен 1 при приведении к unsigned long, то это не настоящий указатель на struct siginfo. Напротив, это специальное значение, указывающее, что сигнал поступает из ядра без дополнительной информации. Ядро никогда не распределяет память под собственные нужды в младшей странице (см. главу 8), поэтому в качестве такого специального значения годится любой адрес, не превышающий 4096 и не равный 0, т.е. NULL.
Во-вторых, во многих местах условия место более общей операции логического неравенства (!=) занимает поразрядная операция XOR (^). В данном случае значение обеих операций одно и то же, поскольку если хотя бы один разряд в сравниваемых целочисленных значениях будет отличаться, тогда в результате выполнения XOR появится хотя бы один разряд, равный 1; это означает, что результат ненулевой и, следовательно, логически истинен. Причина применения XOR, возможно, связана с тем, что старые версии gcc для ^ генерировали более эффективный код, нежели для !=, хотя сейчас это не наблюдается.
28248: Игнорирование сигнала 0 и отказ в отправлении сигнала мертвому процессу (т.е. процессу, который уже завершен, но пока еще не удален из структур данных системы; более подробную информацию о процессах можно найти в главе 7).
28252: Перед отправкой некоторых сигналов должна производится небольшая дополнительная работа. Именно в этом switch она и делается.
28253: Если посылается SIGKILL или SIGCONT, send_sig_info пробуждает процесс (т.е. позволяет ему выполняться вновь, если он пребывал в состоянии останова).
28257: Установка кода завершения для процесса в 0; если процесс был остановлен сигналом SIGSTOP, поле кода завершения используется для взаимодействия сигнала останова с родительским процессом.
28258: Отмена всех ожидающих SIGSTOP (останов по запросу отладчика), SIGTSTP (останов по запросу от клавиатуры, например после нажатия Ctrl+Z), SIGTTIN (фоновый процесс пытается читать из TTY) и SIGTTOU (фоновый процесс пытается записывать в TTY); сложились условия, которые остановили процесс и возможной реакцией на станов стал SIGCONT или SIGKILL.
28263: Обращение к recalc_sigpending (строка 16654) для выяснения, остались ли после удаления еще какие-либо ожидающие сигналы.
28266: В предыдущем случае по прибытию SIGCONT или SIGKILL отменялись четыре сигнала. Частично ради симметрии, если поступает один из этих четырех сигналов, отменяются все ожидающие SIGCONT. Однако, SIGKILL не отменяется, поскольку SIGKILL принципиально не может ни блокироваться, ни отменяться.
28281: Если процесс-получатель желает, и это разрешено, проигнорировать пришедший сигнал, сигнал игнорируется.
28284: Сигналы не реального времени не очередизуются, а это означает, что если второй экземпляр определенного процесса поступает до завершения обработки первого экземпляра, то второй экземпляр игнорируется. Как раз это здесь и выполняется (вспомните, что набор ожидающих сигналов для конкретного процесса хранится в поле signal структуры struct task_struct).
28304: А вот сигналы реального времени — очередизуются, но с определенными ограничениями. Наиболее важное ограничение — это настраиваемый верхний предел количества сигналов, которые могут присутствовать в очереди одновременно; это max_queued_signals, определяемый в строке 28007 и изменяемый при помощи характеристики sysctl. Если имеется место для помещения в очередь дополнительных сигналов, распределяется структура struct signal_queue.
Почему на первом месте находится максимальное количество присутствующих в очереди сигналов? Для того чтобы избежать ситуаций, связанных с отказом обслуживания. Если не предусмотреть такой предел, пользователи могут посылать сигналы реального времени до тех пор, пока не исчерпается память ядра и ядро попросту не сможет далее обслуживать процессы.
28310: Если элемент очереди распределен, send_sig_info должна записать в него информацию о сигнале.
28311: Добавление информации в очередь достаточно прямолинейно: send_sig_info увеличивает глобальное количество ожидающих сигналов и затем добавляет новый элемент в очередь сигналов для процесса-получателя.
28315: Заполнение поля info элемента очереди на основе аргумента info, передаваемого в send_sig_info.
28316: Значение 0 (NULL) означает, что сигнал отправлен пользователем и, возможно, был передан с использованием одной из обратно-совместимых функций посылки сигналов, которые определены в строках с 28513 по 28544. Результирующая siginfo_t содержит относительно очевидные значения.
28323: Значение 1 обозначает тот факт, что сигнал поступил от ядра, причем опять-таки, с использованием обратно-совместимых функций посылки сигналов. Как и в предыдущем случае, результирующая siginfo_t содержит относительно очевидные значения.
28331: В нормальном случае send_sig_info получает реальную siginfo_t и может преспокойно копировать ее в элемент очереди.
28334: Не распределен ни один элемент очереди — либо kmem_cache_alloc возвратила NULL в строке 28306 по причине нехватки памяти в системе, либо send_sig_info даже не пыталась распределить элемент, поскольку максимальное количество сигналов в очереди уже достигнуто. Так или иначе, но функция send_sig_info выполняет те же вещи: вне зависимости от того, отправлен ли сигнал ядром, либо сигнальными функциями старого стиля (например, kill), send_sig_info возвращает код ошибки EAGAIN. Этот код ошибки уведомляет отправителя, что в данный момент сигнал не может быть помещен в очередь, однако отправитель может попытаться послать тот же сигнал позже. В противном случае send_sig_info доставляет сигнал, не помещая его в очередь.
28345: В конечном итоге, send_sig_info фактически готова доставить сигнал. Первоначально сигнал заносится в набор ожидающих сигналов для данного процесса. Следует заметить, что упомянутое занесение будет иметь место даже в случае, если сигнал заблокирован, — немного странно. Однако, для такого поведения есть все основания: ядро поддерживает функцию sys_sigpending (строка 28981), которая дает возможность процессам запрашивать, какие сигналы доставлялись заблокированными.
28346: Если сигнал не является заблокированным, процесс будет уведомлен о его доставке. Соответственно, устанавливается его флаг sigpending.
28370: Если процесс ожидал прибытия сигнала, а сигнал теперь ожидает процесса, последний пробуждается путем вызова функции wake_up_process (строка 26356) и может приступать к обработке сигнала.
28386: Функция force_sig_info используется ядром для обеспечения принудительного получения сигнала процессом вне зависимости, желает он того или нет. Одно из применений функции связано с принудительным получением процессом сигнала SIGSEGV в случае, когда происходит разыменовывание ошибочного указателя (см. строку 7070, где находится обращение к обратно-совместимой функции force_sig, но force_sig реализована полностью в терминах force_sig_info). Аргументы force_sig_info — те же, что и в send_sig_info, причем означают то же самое.
28392: Если процесс является мертвым, то отправить ему сигнал не сможет даже ядро; попытка отправки отвергается.
28397: Если процесс задумал проигнорировать сигнал, force_sig_info заставляет его отказаться от этой затеи, переводя его в состояние, соответствующее стандартным реакциям на сигналы. Это не настоль безобидно, как может показаться: в случаях, когда эту функцию использует ядро, стандартной реакцией на сигнал будет уничтожение процесса.
28399: Удаление сигнала и набора заблокированных сигналов в t.
28402: Сейчас force_sig_info устанавливает такие условия, что t обязана принять сигнал, поэтому сигнал может быть доставлен с использованием send_sig_info. Однако, в случае изменения реализации send_sig_info, сигнал может и не добраться до получателя, так что эти две функции должны изменяться согласовано.
16654: Эта функция пересчитывает флаг sigpending процесса; она вызывается при изменении наборов signal или blocked, связанных с процессом.
16676: В простейшем случае recalc_sigpending выполняет поразрядное И (AND) набора signal с инверсией набора blocked. (Инверсия набора blocked дает в результате набор разрешенных сигналов allowed.) Другие случаи представляют собой простые обобщения рассмотренного.
16679: Если в результате выполнения предшествующих операций в ready остается хотя бы один разряд, равный 1, это значит, что в наборе ожидающих сигналов имеется, по крайней мере, один незаблокированный сигнал; в таком случае recalc_sigpending взводит флаг sigpending.
Поскольку для recalc_sigpending требуется знать, имеется ли хотя бы один ожидающий сигнал (не количество, а лишь факт наличия одного), в нетривиальных случаях код мог бы остановить выполнение изменений в ready (например, прервав цикл в строке 16662) как только ready получит ненулевое значение. Однако, все выигрыши, которые получаются от такого рода оптимизации, тут же поглощаются накладными расходами от дополнительных проверок условий. В этой связи и по причине небольших размеров, _NSIG_WORDS, код работает быстрее, чем кажется на первый взгляд.
28183: ignored_signal помогает send_sig_info принять решение, посылать ли процессу сигнал.
28189: Если процесс трассируется родителем (скажем, отладчиком) или сигнал присутствует в наборе заблокированных сигналов процесса, он не может быть проигнорирован. Второе утверждение несколько неожиданно: если сигнал заблокирован, будет ли send_sig_info (а также и ignored_signal) его игнорировать? Так получается, что нет. Все, что в этих функциях понимается под игнорированием сигнала, сводится к установке соответствующего разряда в наборе signal, относящемся к процессу. Как было показано ранее, поддержка системного вызова sigpending требует, чтобы ядро устанавливало упомянутый разряд, если сигнал был доставлен заблокированным. Отсюда и следует, что заблокированные сигналы игнорироваться не могут.
28194: Если процесс является мертвым, сигнал игнорируется. Эта проверка не является необходимой, поскольку такая ситуация уже была отслежена в строке 28248, перед вызовом ignored_signal.
28199: В большинстве случаев поведение SIG_DFL (стандартное) заключается в обработке сигнала, а не в игнорировании его. Несложно заметить, что исключениями являются SIGCONT, SIGWINCH, SIGCHLD и SIGURG.
28207: Процессам разрешено игнорировать большинство сигналов, но не SIGCHLD. По отношению к SIGCHLD стандарт POSIX придает SIG_IGN специальный смысл, как задокументировано в строке 28831. Упоминаемое здесь «автоматическое отсечение дочерних процессов» выполняется в строке 3426.
28211: В общем случае ignored_signal предположительно имеет реальный указатель на функцию, а не одно из псевдозначений SIG_DFL или SIG_IGN. Следовательно, сигнал связывается с пользовательским обработчиком, а это означает, что процесс желает обработать сигнал. Возвращается 0, указывающий, что сигнал не игнорируется.
3364: do_signal — место, где сигнал доставляется процессу. Эта функция вызывается из многих мест в ядре — в строках 203 и 211, как рассматривалось в главе 5, а также в строках 2797 и 2827. Общее, что эти случаи имеют, — это обработка текущим процессом ожидающего сигнала (если таковой имеется).
3375: Если oldset не равен NULL, он используется для возврата набора заблокированных сигналов в текущем процессе. Поскольку do_signal набор заблокированных сигналов не изменяет, можно просто возвратить указатель на существующий набор.
3378: Вход в цикл, который тянется практически до конца функции (строка 3478). Существует всего два пути выхода из цикла: когда все сигналы, требующие обработки, подошли к концу, или за счет обработки одного сигнала.
3382: Удаление сигнала из очереди при помощи dequeue_signal (строка 28060). Функция dequeue_signal возвращает либо 0, либо число сигналов для обработки, а также заполняет всю дополнительную информацию в info.
3385: Если больше нет ожидающих сигналов, цикл завершается. Обычно это происходит не после первой итерации.
3388: Если текущий процесс трассируется родителем (скажем, отладчиком) и этот сигнал — не SIGKILL, который блокировке не подлежит, родитель процесса должен быть уведомлен о доставке сигнала.
3391: Номер сигнала, доставленного для дочернего процесса, передается родителю в поле exit_code дочернего процесса; родитель будет собирать их с использованием sys_wait4 (строка 23327, которая рассматривается в главе 7). do_signal останавливает дочерний процесс, обращается к notify_parent (строка 28548) для отправки родителю сигнала SIGCHLD и затем вызывает функцию планировщика schedule (строка 26686, см. главу 7), чтобы предоставить остальным процессам (в частности, родителю) возможность продолжить выполнение. Функция schedule будет уступать ЦП другому процессу, поэтому возврата из нее не будет до тех пор, пока ядро не выполнит переключение вновь на этот процесс.
3397: Если отладчик отменяет сигнал, do_signal его здесь обрабатывать не будет и цикл продолжается.
3402: Возможно, возник SIGSTOP из-за того, что выполняется трассировка процесса. Нет необходимости его обрабатывать, поэтому цикл продолжается.
3406: Если отладчик изменил номер сигнала, который должен обрабатываться do_signal, do_signal заполняет info в соответствие с новой информацией.
3415: Как гласит комментарий, если новый сигнал заблокирован, он повторно помещается в очередь и цикл продолжается. В противном случае управление передается на следующий код.
3421: В этот момент либо процесс не трассируется, либо он трассируется, но получил сигнал SIGKILL, либо управление передалось из предыдущего блока. В любом из перечисленных случаев do_signal имеет сигнал, который сейчас будет обработан. Все начинается с чтения структуры struct k_sigaction, из которой получается информация о том, как должен обрабатываться конкретный номер сигнала.
3423: В том случае когда процесс пытается проигнорировать сигнал, do_signal продолжает цикл, если только это не сигнал SIGCHLD. Почему здесь не проверяется также, не пытается ли процесс проигнорировать SIGKILL, который по определению нельзя ни игнорировать, ни блокировать? Ответ заключается в том, что действие, соответствующее SIGKILL, никогда не может быть SIG_IGN, и тем более не SIG_DFL — это гарантируется в строке 28807 (в функции do_sigaction). Таким образом, если действием является SIG_IGN, номером сигнала не может быть SIGKILL.
3426: Как гласит комментарий в строке 28820, стандарт POSIX определяет, что действие «проигнорировать» для SIGCHLD означает автоматически отсечь дочерний процесс. Дочерний процесс отсекается при помощи sys_wait4 (строка 23327, см. главу 7) и цикл продолжается.
3435: Процесс выполняет для данного сигнала стандартное действие. Стандартные действия для всех сигналов, полученные от специального процесса init, сводятся к полному игнорированию сигнала.
3439: Стандартные действия для сигналов SIGCONT, SIGCHLD и SIGWINCH — это не делать ничего, следовательно, просто продолжить цикл.
3442: Для сигналов SIGTSTP, SIGTTIN и SIGTTOU стандартные действия изменяются. В том случае когда группа, к которой принадлежит данный процесс, оказывается висячей (ни с чем не связана) — это может означать, что она не присоединена к TTY — POSIX определяет, что стандартным действием для этих терминальных сигналов должно быть игнорирование. Если же группа процессов не является висячей, то стандартной реакцией на сигналы должен быть останов процесса — то же самое, что и случай с SIGSTOP, поэтому именно туда передается управление.
3447: В ответ на SIGSTOP (либо в результате передачи управления из предыдущего случая) do_signal останавливает процесс. Кроме того, выполняется уведомление родительского процесса об останове одного из его дочерних процессов, если только родительский процесс не отменил необходимость такого уведомления. Как и в строке 3394, выполняется вызов schedule для передачи ЦП другим процессам. После того как ядро вновь вернет ЦП текущему процессу, цикл продолжит свою работу и займется вытаскиванием из очереди следующего сигнала.
Это несколько неожиданно — я думал, что когда произойдет возврат из schedule, цикл должен завершиться, поскольку сигнал обработан. Кажется, рациональнее было бы пробуждать остановленный процесс только по приходу сигнала, например SIGCONT, чтобы можно было также и проверить и обработать сигнал.
3456: Стандартная реакция на другие сигналы сводится к завершению процесса. Некоторые сигналы сначала порождают процесс, чтобы попытаться записать дамп ядра (см. главу 8) — это SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGFPE и SIGSEGV. Если данный двоичный формат (см. главу 7) знает, как записать дамп и дамп завершается успешно, в коде завершения процесса устанавливается соответствующий разряд, указывающий, что перед завершением процесс успел записать дамп. Далее управление передается на общий случай, который и завершает процесс. Из функции do_exit (строка 23267, см. главу 7) никогда не происходит возврата — отсюда и комментарий «NOTREACHED» в строке 3471.
3476: В этот момент do_signal изъяла из очереди сигнал, который не ассоциируется ни с действием SIG_IGN, ни с действием SIG_DFL. Единственное, что можно предположить, что сигнал имеет пользовательский обработчик. do_signal обращается к handle_signal (строка 3314), чтобы вызвать пользовательский обработчик сигнала, и возвращает 1, уведомляя отправителя о факте обработки сигнала.
3481: Здесь do_signal не может получить из очереди сигнал для текущего процесса. (В эту строку можно попасть только после break в строке 3386.) Если процесс прерван из середины системного вызова, do_signal настраивает таким образом, что системный вызов сможет возобновить выполнение.
3490: Возврат 0, информирующего отправителя о том, что do_signal не обработала ни одного сигнала.
28060: Функция dequeue_signal изымает сигнал из сигнальной очереди процесса, пропуская те сигналы, которые определены mask. Функция возвращает номер сигнала и соответствующую siginfo_t через указатель info.
28071: Установка нескольких псевдонимов во избежание повторных разыменований: s — это набор ожидающих сигналов для процесса (помните, что некоторые из них могут быть также и заблокированными), a m — маскирующий набор. В частности, выражение *s, несколько раз встречающееся в функции, — ни что иное как ускоренная версия current->signal.sig[0].
28073: Внутри этого оператора switch значение sig устанавливается равным первому ожидающему сигналу. Этот простейший случай проще всего доступен для понимания; остальные случаи представляют собой лишь его обобщения.
28091: Вот он простейший случай: поразрядная операция И между набором ожидающих сигналов и проинвертированной маской, после чего результат сохраняется во временной переменной х; теперь х представляет собой набор ожидающих сигналов, непроигнорированных маской. Если х не равно 0, значит, такой ожидающий сигнал существует (х содержит, по крайней мере, один установленный разряд); dequeue_signal получает соответствующий номер сигнала с использованием ffz (в книге не рассматривается) и приводит его к нумерации, начиная с 1. Результат сохраняется в sig. Как уже упоминалось, другие случаи являются просто обобщениями данного; важно только то, что в каждом из них sig получает набор — состояние же прочих переменных (i, s, m и х) с этого момента во внимание не принимается. Если после выполнения оператора switch значение sig равно 0, значит, при помощи маски не удалось найти ни одного ожидающего сигнала.
28097: Если сигнал задерживается, dequeue_signal будет пытаться изъять его из очереди, reset отслеживает, удаляет ли dequeue_signal сигнал из очереди задержанных сигналов для процесса. Начальная установка reset в 1 — это просто предположение, что reset будет изменяться по мере выполнения функции.
28107: Для сигналов не реального времени ядро не сохраняет оригинальную siginfo_t (даже если она существует), поэтому dequeue_signal придется реконструировать как можно больше информации. К сожалению, в данной реализации это не настоль много — только собственно номер сигнала. Остаток полей просто обнуляется.
28118: В случае сигналов реального времени siginfo_t находится где-то рядом. В ее поисках dequeue_signal сканирует sigqueue процесса.
28122: Если удается найти siginfo_t, dequeue_signal изымает сигнал из очереди, копирует siginfo_t сигнала в info и освобождает память, занятую элементом очереди.
28129: Если очередь не содержит более ни одного экземпляра данного сигнала, это означает, что сигнал больше не является задержанным. Однако dequeue_signal все же проходит по очереди, убеждаясь, что это так. Эта функция сканирует элементы очереди на предмет присутствия в них других экземпляров данного сигнала. Если таковые найдены, dequeue_signal сбрасывает флаг reset — единственное условие завершения.
28142: Из очереди изымался сигнал реального времени, однако он не найден в очереди задержанных сигналов для процесса по причинам, указанным в коде. Сейчас функция dequeue_signal ведет себя так же, как и по отношению к сигналу не реального времени (т.е. знает, что сигнал доступен, но не знает, где он размещается) и предпринимает те же действия по ответу, помещая в info только номер сигнала.
28150: Если не сбросить флаг reset, сигнал обслуживается и удаляется из набора задержанных сигналов для процесса.
28152: Сигнал вытолкнут из очереди, поэтому dequeue_signal должна пересчитать флаг sigpending процесса. Мне здесь видится возможность проведения небольшой оптимизации: dequeue_signal должна делать упомянутое действие только в случае истинного значения reset. recalc_sigpending подсчитывает ответы, полученные ею из наборов заблокированных и ожидающих сигналов для процесса; набор заблокированных сигналов не изменялся, поэтому dequeue_signal должна обращаться к recalc_sigpending лишь при изменении набора ожидающих сигналов. Если значение reset ложно, значит, не изменялся набор ожидающих сигналов, поэтому необходимость в вызове recalc_sigpending отпадает.
28163: При помощи оператора switch не удалось найти ни одного сигнала, т.е. задержанных сигналов нет. Кроме того, в целях внутренней проверки корректности, dequeue_signal гарантирует, что ядро не думает, что сигнал задержан для задачи.
28174: Возврат количества сигналов, изъятых из очереди, т.е. 0 означает их отсутствие.
28548: notify_parent отыскивает родителя процесса и информирует его об изменении состояния дочернего процесса — как правило, дочерний процесс либо остановлен, либо уничтожен.
28553: Заполняет внутреннюю переменную info информацией о контексте, в котором произошел сигнал.
28564: В случае если дочерний процесс завершился, why устанавливается в значения, указывающие на факт сохранения процессом дампа, на факт уничтожения процесса по сигналу или на факт завершения процесса по собственному желанию.
28572: Аналогично, если процесс остановлен по сигналу, why устанавливается соответствующим образом.
28578: Предполагается, что предыдущие случаи покрыли все возможности. Если же нет, функция печатает предупредительное сообщение и продолжает работу; в таком случае why примет значение SI_KERNEL в строке 28562.
28586: Отправка сигнала родителю процесса. Следующая строка обеспечивает пробуждение всех процессов, ожидающих данного дочернего, предлагая в их распоряжение ЦП.
3314: handle_signal вызывается из функции do_signal, когда требуется выполнить обращение к пользовательскому обработчику сигналов.
3338: Установка фрейма стека, в котором будет выполняться пользовательский обработчик сигналов. Если процесс запрашивает любую дополнительную информацию, которую может сообщить ядро, связанную с начальным адресом и контекстом сигнала, фрейм стека устанавливается при помощи setup_rt_frame (строка 3231); в противном случае вызывается setup_frame (строка 3161). Обе последовательности действий обеспечивают корректную передачу управления обработчику сигналов и корректный возврат из него в соответствующую позицию кода.
3343: Если флаг SA_ONESHOT установлен, обработчик сигналов будет выполняться только один раз. (Следует заметить, что sys_signal, реализация системного вызова signal, использует обработчики с типом SA_ONESHOT — см. строку 29063.) В данном случае восстанавливается стандартное действие.
3346: SA_NODEFER означает, что в течение выполнения обработчика данного сигнала дополнительные сигналы блокироваться не будут. Если этот разряд не установлен, в набор заблокированных процессов добавляются дополнительные разряды.
netlib.narod.ru | < Назад | Оглавление | Далее > |