setjmp, sigsetjmp, longjmp, siglongjmp -
выполняет
нелокальный
переход
Standard C library (
libc,
-lc)
#include <setjmp.h>
int setjmp(jmp_buf env);
int sigsetjmp(sigjmp_buf env, int savesigs);
[[noreturn]] void longjmp(jmp_buf env, int val);
[[noreturn]] void siglongjmp(sigjmp_buf env, int val);
setjmp():
смотрите
ЗАМЕЧАНИЯ.
sigsetjmp():
_POSIX_C_SOURCE
Функции,
описываемые
в этой
странице,
используются
для
выполнения
«нелокального
goto»: передачи
исполнения
из одной
функции в
заранее
определённое
место
другой.
Функция
setjmp()
динамически
устанавливает
точку для
будущей
передачи
исполнения,
а
longjmp()
выполняет
передачу
исполнения.
Функция
setjmp()
сохраняет
различную
информацию
об
окружении
вызова
(обычно,
указатель
стека,
указатель
инструкции,
значения
других
регистров
и маску
сигналов) в
буфер
env для
последующего
использования
в
longjmp(). В этом
случае
setjmp()
возвращает
0.
Функция
longjmp()
использует
информацию,
сохранённую
в
env, для
передачи
управления
обратно в
точку,
откуда
была
вызвана
setjmp(),
и
восстанавливает
(«отматывает»)
стек до
состояния
на время
вызова
setjmp().
Также, в
зависимости
от
реализации
(смотрите
ЗАМЕЧАНИЯ),
значения
некоторых
регистров
маска
сигналов
процесса
могут быть
восстановлены
в их
состояние
на момент
вызова
setjmp().
После
успешного
вызова
longjmp()
выполнение
продолжается
как если бы
setjmp() была
вызвана
второй раз.
Этот
«фиктивный»
возврат
можно
распознать
от
настоящего
вызова
setjmp(),
так как
«фиктивный»
возврат
возвращает
значение,
указанное
в
val. Если
программист
ошибочно
передаст
значение 0 в
val, то
«фиктивный»
возврат
вернёт
вместо
него 1.
Функции
sigsetjmp()
и
siglongjmp() также
выполняют
нелокальные
переходы,
но
предоставляют
предсказуемую
обработку
сигнальной
маски
процесса.
Если, и
только
если,
аргумент
savesigs,
передаваемый
в
sigsetjmp(), не
равен нулю,
то текущая
маска
сигналов
процесса
сохраняется
в
env и будет
восстановлена,
если
позднее
будет
запущена
siglongjmp() с этим
env.
Функции
setjmp()
и
sigsetjmp()
возвращают
0, если
вызывают
явно; при
«фиктивном»
возврате,
который
возникает
после
longjmp()
или
siglongjmp(),
возвращается
ненулевое
значение,
указанное
в
val.
Функции
longjmp()
и
siglongjmp() не
выполняют
возврат.
Описание
терминов
данного
раздела
смотрите в
attributes(7).
Интерфейс |
Атрибут |
Значение |
setjmp(), sigsetjmp() |
Безвредность
в нитях |
MT-Safe |
longjmp(), siglongjmp() |
Безвредность
в нитях |
MT-Safe |
setjmp(),
longjmp(): POSIX.1-2001, POSIX.1-2008, C99.
sigsetjmp(),
siglongjmp(): POSIX.1-2001, POSIX.1-2008.
POSIX does not specify whether
setjmp() will save the signal mask (to be
later restored during
longjmp()). In System V it will not. In 4.3BSD it
will, and there is a function
_setjmp() that will not. The behavior
under Linux depends on the glibc version and the setting of feature test
macros. Before glibc 2.19,
setjmp() follows the System V behavior by
default, but the BSD behavior is provided if the
_BSD_SOURCE feature
test macro is explicitly defined and none of
_POSIX_SOURCE,
_POSIX_C_SOURCE,
_XOPEN_SOURCE,
_GNU_SOURCE, or
_SVID_SOURCE is defined. Since glibc 2.19,
<setjmp.h>
exposes only the System V version of
setjmp(). Programs that need the
BSD semantics should replace calls to
setjmp() with calls to
sigsetjmp() with a nonzero
savesigs argument.
Функции
setjmp()
и
longjmp() можно
использовать
для
обработки
ошибок
внутри
глубоко
вложенных
вызовов
функций
или чтобы
позволить
обработчику
сигналов
передать
управление
в
определённую
точку
программы,
и не
возвращать
исполнение
главной
программе
в точку
прерывания
обработчиком.
В
последнем
случае,
если вы
хотите
сохранить
и
восстановить
маску
сигналов
переносимым
образом, то
используйте
sigsetjmp() и
siglongjmp().
Также
смотрите
раздел про
читаемость
программы
далее.
Компилятор
может
оптимизировать
переменные
в
регистрах
и
longjmp() может
восстановить
значения
регистров
помимо
указателя
стека и
счётчика
программы.
Следовательно,
значения
автоматических
переменных
непредсказуемы
после
вызова
longjmp(),
если они
удовлетворяют
следующим
критериям:
- •
- они
локальны
для
функции,
которая
сделала
соответствующий
вызов setjmp();
- •
- их
значения
изменились
между
вызовами
setjmp() и longjmp(); и
- •
- они не
объявлены
как volatile.
Аналогичные
замечания
относятся
и к
siglongjmp().
Хотя этим и
можно
злоупотребить,
обычный
оператор C
«goto» имеет
преимущество
в виде
лексических
отметок
(оператор goto
и метка
перехода),
которые
позволяют
программисту
легко
понять
поток
выполнения.
Нелокальные
переходы
не имеют
таких
отметок:
многократные
вызовы
setjmp()
могут
использовать
одну
переменную
jmp_buf, то есть
контекст
переменной
может
изменяться
на
протяжении
времени
работы
приложения.
Следовательно,
программисту
придёт
вчитываться
в код для
определения
динамической
точки
перехода
определённого
вызова
longjmp()
(для
облегчения
жизни
программиста
в каждом
вызове
setjmp()
должна
использоваться
уникальная
переменная
jmp_buf).
Дополнительная
сложность:
вызовы
setjmp() и
longjmp() даже
могут быть
в разных
модулях
исходного
кода.
Таким
образом,
нелокальные
переходы
могут
сделать
программу
тяжелее
для
понимания
и
поддержки,
и, если это
возможно,
нужно
использовать
альтернативные
варианты.
Если
функция,
вызвавшая
setjmp()
завершилась
до вызова
longjmp(), то
поведение
не
определено.
Результатом
может
стать
маленький
(или не
очень) хаос.
Если в
многонитевой
программе
вызов
longjmp()
использует
буфер
env,
инициализированный
вызовом
setjmp()
в другой
нити, то
поведение
не
определено.
В POSIX.1-2008 Technical Corrigendum 2
вызовы
longjmp() и
siglongjmp()
добавлены
в список
функций async-signal-safe.
Однако
стандарт
рекомендует
избегать
использования
этих
функций в
обработчиках
сигналов и
указывает,
что если
эти
функции
вызваны из
обработчика
сигналов,
который
прервал
вызов
функции не
async-signal-safe (или её
эквивалент,
например
шагам
exit(3),
который
возникают
при
возврате
из
начального
вызова
main()),
то
поведение
не
определено,
если
программа
далее
вызывает
функцию не
async-signal-safe.
Единственным
способом
избежать
неопределённого
поведения,
является
проверка
следующего:
- •
- После
длинного
перехода
из
обработчика
сигналов
программа
не
вызывает
каких-либо
функций не
async-signal-safe и не
возвращается
из
первоначального
вызова в
main().
- •
- Любой
сигнал, чей
обработчик
выполняет
длинный
переход,
должен
быть
заблокирован
на время
каждого
вызова
функции не
async-signal-safe и не
вызывать
функции не
async-signal-safe после
возврата
из
начального
вызова в
main().
signal(7),
signal-safety(7)
Русский
перевод
этой
страницы
руководства
был сделан
Alexander Golubev <
[email protected]>, Azamat Hackimov
<
[email protected]>, Hotellook, Nikita
<
[email protected]>, Spiros Georgaras <
[email protected]>, Vladislav
<
[email protected]>, Yuri Kozlov <
[email protected]>
и Иван
Павлов <
[email protected]>
Этот
перевод
является
бесплатной
документацией;
прочитайте
Стандартную
общественную
лицензию GNU
версии 3
или более
позднюю,
чтобы
узнать об
условиях
авторского
права. Мы не
несем
НИКАКОЙ
ОТВЕТСТВЕННОСТИ.
Если вы
обнаружите
ошибки в
переводе
этой
страницы
руководства,
пожалуйста,
отправьте
электронное
письмо на
[email protected]