Нелокальные выходы в модулях
Emacs Lisp поддерживает нелокальные выходы, при которых управление программой передаётся из одной точки программы в другую, удалённую точку. См. Нелокальные выходы. Поэтому функции Lisp, вызываемые вашим модулем, могут выполнять нелокальный выход, вызывая signal или throw, и функции вашего модуля должны правильно обрабатывать такие нелокальные выходы. Такая обработка необходима, поскольку программы на C в этих случаях не будут автоматически освобождать ресурсы и выполнять другую очистку; код модуля должен делать это самостоятельно. API модуля предоставляет средства для этого, описанные в данном подразделе. Как правило, они доступны начиная с Emacs 25; для тех из них, которые появились в более поздних выпусках, явно указана первая версия Emacs, в которой они стали частью API.
Когда некоторый код Lisp, вызванный функцией модуля, сигнализирует об ошибке или выполняет throw, нелокальный выход перехватывается, а ожидающий выход и связанные с ним данные сохраняются в окружении. Пока в окружении ожидает нелокальный выход, любая функция API модуля, вызванная с указателем на это окружение, немедленно возвращает управление без выполнения каких-либо действий (исключение составляют функции non_local_exit_check, non_local_exit_get и non_local_exit_clear). Если после этого функция вашего модуля ничего не делает и возвращается в Emacs, ожидающий нелокальный выход заставит Emacs обработать его: сигнализировать об ошибке или выполнить throw к соответствующему catch.
Таким образом, простейшая «обработка» нелокальных выходов в функциях модулей — не предпринимать ничего особенного и позволить остальной части кода выполняться так, как если бы ничего не произошло. Однако это может привести к двум видам проблем:
- Функция вашего модуля может использовать неинициализированные или неопределённые значения, поскольку функции API немедленно возвращают управление, не предоставляя ожидаемых результатов.
- Ваш модуль может допустить утечку ресурсов, поскольку у него может не быть возможности освободить их.
Поэтому мы рекомендуем функциям вашего модуля проверять условия нелокального выхода и обрабатывать их с помощью описанных ниже функций.
-
Функция:
enum emacs_funcall_exitnon_local_exit_check(emacs_env *env) -
Эта функция возвращает тип условия нелокального выхода, сохранённого в env. Возможны следующие значения:
-
emacs_funcall_exit_return Последняя функция API завершилась нормально.
-
emacs_funcall_exit_signal Последняя функция API сигнализировала об ошибке.
-
emacs_funcall_exit_throw Последняя функция API завершилась с помощью
throw.
-
-
Функция:
enum emacs_funcall_exitnon_local_exit_get(emacs_env *env, emacs_value *symbol, emacs_value *data) Эта функция возвращает тип условия нелокального выхода, сохранённого в env, как и
non_local_exit_check, но также возвращает полную информацию о нелокальном выходе, если он есть. Если возвращаемое значение —emacs_funcall_exit_signal, функция сохраняет символ ошибки в*symbol, а данные ошибки — в*data(см. Как сигнализировать об ошибке). Если возвращаемое значение —emacs_funcall_exit_throw, функция сохраняет символ меткиcatchв*symbol, а значениеthrow— в*data. Если возвращаемое значение —emacs_funcall_exit_return, функция ничего не сохраняет в памяти, на которую указывают эти аргументы. Если функции не удаётся выделить память для symbol или data, она сохраняет значение, представляющее символmodule-out-of-memory, в*symbol, сохраняет значение, представляющееnil, в*dataи возвращаетemacs_funcall_exit_signal.
Проверяйте условия нелокального выхода там, где это важно: прежде чем выделять какой-либо ресурс или после выделения ресурса, который может потребоваться освободить, а также в случаях, когда из-за сбоя дальнейшая обработка невозможна или нецелесообразна.
Обнаружив ожидающий нелокальный выход, функция вашего модуля может либо вернуться в Emacs (предварительно выполнив необходимую локальную очистку), либо попытаться восстановиться после нелокального выхода. В этом помогут следующие функции API.
-
Функция:
voidnon_local_exit_clear(emacs_env *env) Эта функция очищает ожидающие условия нелокального выхода и данные из env. После её вызова функции API модуля будут работать в обычном режиме. Используйте эту функцию, если функция вашего модуля может восстановиться после нелокальных выходов из вызываемых ею функций Lisp и продолжить работу, а также перед вызовом любой из следующих двух функций (или любых других функций API, если вы хотите, чтобы они выполняли свои предусмотренные действия при ожидающем нелокальном выходе).
-
Функция:
voidnon_local_exit_throw(emacs_env *env, emacs_value tag, emacs_value value) Эта функция выполняет throw к символу
catchLisp, представленному tag, передавая ему value в качестве возвращаемого значения. Как правило, функция вашего модуля должна вскоре завершиться после вызова этой функции. Один из вариантов использования этой функции — повторно выполнить throw для нелокального выхода из одной из вызванных функций API или Lisp.
-
Функция:
voidnon_local_exit_signal(emacs_env *env, emacs_value symbol, emacs_value data) Эта функция сигнализирует об ошибке, представленной символом ошибки symbol, с указанными данными ошибки data. Функция модуля должна вскоре завершиться после вызова этой функции. Эта функция может быть полезна, например, для сигнализации об ошибках из функций модуля в Emacs.
Copyright © 1990-1996, 1998-2026 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Module-Nonlocal.html