41.10 Sentinels: Обнаружение изменений состояния процесса

Процессный сентинел (process sentinel) — это функция, которая вызывается всякий раз, когда ассоциированный процесс изменяет свое состояние по любой причине, включая сигналы (отправленные Emacs или вызванные собственными действиями процесса), которые завершают, останавливают или продолжают процесс. Процессный сентинел также вызывается, если процесс завершается. Сентинел принимает два аргумента: процесс, для которого произошло событие, и строку, описывающую тип события.

Если для процесса не была указана функция сентинела, будет использоваться функция сентинела по умолчанию, которая вставляет сообщение в буфер процесса с именем процесса и строкой, описывающей событие.

Строка, описывающая событие, выглядит как одна из следующих (но это не исчерпывающий список строк событий):

Сентинел выполняется только пока Emacs ожидает (например, ввода из терминала, или истечения времени, или вывода процесса). Это позволяет избежать ошибок времени, которые могут возникнуть при выполнении сентинелов в случайных местах в середине других программ Lisp. Программа может ждать, чтобы сентинелы выполнились, вызвав sit-for или sleep-for (см. Ожидание истечения времени или ввода), или accept-process-output (см. Прием вывода от процессов). Emacs также позволяет сентинелам выполняться, когда цикл команд читает ввод. delete-process вызывает сентинел, когда он завершает запущенный процесс.

Emacs не хранит очередь из нескольких причин для вызова сентинела одного процесса; он записывает только текущее состояние и факт изменения. Поэтому два изменения состояния, произошедшие подряд, могут вызвать сентинел только один раз. Однако завершение процесса всегда вызовет сентинел ровно один раз. Это потому что состояние процесса не может измениться после завершения.

Emacs явно проверяет наличие вывода от процесса перед выполнением процессного сентинела. Как только сентинел выполняется из-за завершения процесса, больше никакого вывода от процесса не может поступить.

Сентинел, который записывает вывод в буфер процесса, должен проверить, жив ли буфер. Если он попытается вставить данные в мертвый буфер, он получит ошибку. Если буфер мертв, (buffer-name (process-buffer process)) возвращает nil.

Выход из работы обычно подавляется внутри сентинела — иначе эффект нажатия C-g на уровне команд или выхода из пользовательской команды был бы непредсказуемым. Если вы хотите разрешить выход внутри сентинела, привяжите inhibit-quit к nil. В большинстве случаев правильный способ сделать это — использовать макрос with-local-quit. См. Выход из работы.

Если во время выполнения сентинела происходит ошибка, она перехватывается автоматически, чтобы не остановить выполнение любых программ, которые работали, когда был запущен сентинел. Однако, если debug-on-error не равен nil, ошибки не перехватываются. Это позволяет использовать отладчик Lisp для отладки сентинела. См. Отладчик Lisp. Если ошибка перехвачена, Emacs приостанавливается на process-error-pause-time секунд, чтобы пользователь увидел ошибку. См. Создание асинхронного процесса.

Пока сентинел выполняется, процессный сентинел временно устанавливается в nil, чтобы сентинел не выполнялся рекурсивно. По этой причине сентинел не может указать новый сентинел.

Обратите внимание, что Emacs автоматически сохраняет и восстанавливает данные сопоставления во время выполнения сентинелов. См. Данные сопоставления.

Функция: set-process-sentinel process sentinel

Эта функция ассоциирует sentinel с process. Если sentinel равен nil, то процесс будет иметь сентинел по умолчанию, который вставляет сообщение в буфер процесса при изменении состояния процесса.

Изменения в процессных сентинелах вступают в силу немедленно — если сентинел должен был быть вызван, но еще не был вызван, и вы указываете новый сентинел, то последующий вызов сентинела будет использовать новый.

(defun msg-me (process event)
   (princ
     (format "Process: %s had the event '%s'" process event)))
(set-process-sentinel (get-process "shell") 'msg-me)
     ⇒ msg-me
(kill-process (get-process "shell"))
     -| Process: #<process shell> had the event 'killed'
     ⇒ #<process shell>
Функция: process-sentinel process

Эта функция возвращает сентинел process.

Если необходимо передать изменение состояния процесса нескольким сентинелам, можно использовать add-function для объединения существующего сентинела с новым. См. Настройка функций Emacs Lisp.

Функция: waiting-for-user-input-p

Пока выполняется сентинел или функция фильтра, эта функция возвращает не-nil, если Emacs ожидал ввода с клавиатуры от пользователя на момент вызова сентинела или функции фильтра, или nil, если не ожидал.