Функции вызова в стандартной библиотеке C, отличные от прерывания, _Exit и сигнала из обработчика сигнала
Функции вызова в стандартной библиотеке C кроме прерывания, _Exit и сигнала из обработчика сигнала.[1]
Эта проверка проверяет на наличие следующих проблем:
Функция, вызываемая от обработчика сигнала, не асинхронно-безопасна (строго).
Функция, вызываемая от обработчика сигнала, не асинхронно-безопасна.
Функция, вызываемая от обработчика сигнала, не асинхронно-безопасного (строгого), возникает, когда обработчик сигнала вызывает функцию, которая не асинхронно-безопасна в соответствии со стандартом C. Асинхронно-безопасная функция может быть прервана в любой момент ее выполнения, затем вызвана снова, не вызывая несогласованного состояния. Он также может правильно обрабатывать глобальные данные, которые могут находиться в несогласованном состоянии.
При выборе проверки Function, вызываемой от обработчика сигнала, не асинхронно-безопасного, проверка обнаруживает вызовы функций, которые не являются асинхронно-безопасными в соответствии со стандартом POSIX. Функция, вызываемая от обработчика сигнала, не асинхронно-безопасного (строгого), не вызывает дефект для этих случаев. Функция, вызываемая от обработчика сигнала, не асинхронно-безопасного (строгого), вызывает дефект для функций, которые асинхронно-безопасны в соответствии со стандартом POSIX, но не согласно стандарту C.
Если обработчик сигнала вызывает другую функцию, которая вызывает асинхронно-небезопасную функцию, дефект появляется при вызове функции в обработчике сигнала. Трассировка дефекта показывает полный путь от обработчика сигнала до асинхронно-небезопасной функции.
Когда вызывается обработчик сигнала, выполнение программы прерывается. После завершения работы обработчика выполнение программы возобновляется в точке прерывания. Если функция выполняется во время прерывания, вызов ее из обработчика сигнала является неопределенным поведением, если только это не асинхронно-безопасно.
Стандарт C определяет следующие функции как асинхронно-безопасные. Можно вызвать эти функции из обработчика сигнала:
abort()
_Exit()
quick_exit()
signal()
raise()
Обработчик внутреннего сигнала#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <setjmp.h>
#include <syslog.h>
#include <unistd.h>
void SIG_ERR_handler(int signum)
{
int s0 = signum;
/* SIGTERM specific handling */
}
void sig_handler(int signum)
{
int s0 = signum;
/* Call raise() */
if (raise(SIGTERM) != 0) {
/* Handle error */
}
}
int finc(void)
{
if (signal(SIGTERM, SIG_ERR_handler) == SIG_ERR)
{
/* Handle error */
}
if (signal(SIGINT, sig_handler) == SIG_ERR)
{
/* Handle error */
}
/* Program code */
if (raise(SIGINT) != 0)
{
/* Handle error */
}
/* More code */
return 0;
}
В этом примере sig_handler
вызывает raise()
при захвате сигнала. Если обработчик захватывает другой сигнал во время raise()
выполняется, поведение программы не определено.
raise()
в обработчике сигналовСогласно стандарту C, единственные функции, которые можно безопасно вызвать с обработчика сигнала abort()
, _Exit()
, quick_exit()
, и signal()
.
#include <signal.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <setjmp.h> #include <syslog.h> #include <unistd.h> void SIG_ERR_handler(int signum) { int s0 = signum; /* SIGTERM specific handling */ } void sig_handler(int signum) { int s0 = signum; } int func(void) { if (signal(SIGTERM, SIG_ERR_handler) == SIG_ERR) { /* Handle error */ } if (signal(SIGINT, sig_handler) == SIG_ERR) { /* Handle error */ } /* Program code */ if (raise(SIGINT) != 0) { /* Handle error */ } /* More code */ return 0; }
Функция, вызываемая от обработчика сигнала, не асинхронного-безопасного, возникает, когда обработчик сигнала вызывает функцию, которая не является асинхронной-безопасной в соответствии со стандартом POSIX. Асинхронно-безопасная функция может быть прервана в любой момент ее выполнения, затем вызвана снова, не вызывая несогласованного состояния. Он также может правильно обрабатывать глобальные данные, которые могут находиться в несогласованном состоянии.
Если обработчик сигнала вызывает другую функцию, которая вызывает асинхронно-небезопасную функцию, дефект появляется при вызове функции в обработчике сигнала. Трассировка дефекта показывает полный путь от обработчика сигнала до асинхронно-небезопасной функции.
Когда вызывается обработчик сигнала, выполнение программы прерывается. После завершения работы обработчика выполнение программы возобновляется в точке прерывания. Если функция выполняется во время прерывания, вызов ее из обработчика сигнала является неопределенным поведением, если только это не асинхронно-безопасно.
Стандарт POSIX определяет эти функции как асинхронно-безопасные. Можно вызвать эти функции из обработчика сигнала.
_exit() | getpgrp() | setsockopt() |
_Exit() | getpid() | setuid() |
abort() | getppid() | shutdown() |
accept() | getsockname() | sigaction() |
access() | getsockopt() | sigaddset() |
aio_error() | getuid() | sigdelset() |
aio_return() | kill() | sigemptyset() |
aio_suspend() | link() | sigfillset() |
alarm() | linkat() | sigismember() |
bind() | listen() | signal() |
cfgetispeed() | lseek() | sigpause() |
cfgetospeed() | lstat() | sigpending() |
cfsetispeed() | mkdir() | sigprocmask() |
cfsetospeed() | mkdirat() | sigqueue() |
chdir() | mkfifo() | sigset() |
chmod() | mkfifoat() | sigsuspend() |
chown() | mknod() | sleep() |
clock_gettime() | mknodat() | sockatmark() |
close() | open() | socket() |
connect() | openat() | socketpair() |
creat() | pathconf() | stat() |
dup() | pause() | symlink() |
dup2() | pipe() | symlinkat() |
execl() | poll() | sysconf() |
execle() | posix_trace_event() | tcdrain() |
execv() | pselect() | tcflow() |
execve() | pthread_kill() | tcflush() |
faccessat() | pthread_self() | tcgetattr() |
fchdir() | pthread_sigmask() | tcgetpgrp() |
fchmod() | quick_exit() | tcsendbreak() |
fchmodat() | raise() | tcsetattr() |
fchown() | read() | tcsetpgrp() |
fchownat() | readlink() | time() |
fcntl() | readlinkat() | timer_getoverrun() |
fdatasync() | recv() | timer_gettime() |
fexecve() | recvfrom() | timer_settime() |
fork() | recvmsg() | times() |
fpathconf() | rename() | umask() |
fstat() | renameat() | uname() |
fstatat() | rmdir() | unlink() |
fsync() | select() | unlinkat() |
ftruncate() | sem_post() | utime() |
futimens() | send() | utimensat() |
getegid() | sendmsg() | utimes() |
geteuid() | sendto() | wait() |
getgid() | setgid() | waitpid() |
getgroups() | setpgid() | write() |
getpeername() | setsid() |
Функции, не указанные в предыдущей таблице, не являются асинхронно-безопасными и не должны вызываться из сигнальной трубки.
printf()
Обработчик внутреннего сигнала#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <setjmp.h>
#include <syslog.h>
#include <unistd.h>
#define SIZE20 20
extern volatile sig_atomic_t e_flag;
void display_info(const char *info)
{
if (info)
{
(void)fputs(info, stderr);
}
}
void sig_handler(int signum)
{
/* Call function printf() that is not
asynchronous-safe */
printf("signal %d received.", signum);
e_flag = 1;
}
int main(void)
{
e_flag = 0;
if (signal(SIGINT, sig_handler) == SIG_ERR)
{
/* Handle error */
}
char *info = (char *)calloc(SIZE20, sizeof(char));
if (info == NULL)
{
/* Handle Error */
}
while (!e_flag)
{
/* Main loop program code */
display_info(info);
/* More program code */
}
free(info);
info = NULL;
return 0;
}
В этом примере sig_handler
вызывает printf()
при захвате сигнала. Если обработчик захватывает другой сигнал во время printf()
выполняется, поведение программы не определено.
Используйте обработчик сигнала, чтобы задать только значение флага. e_flag
имеет тип «летучий» sig_atomic_t
. sig_handler
может безопасно получить к нему доступ асинхронно.
#include <signal.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <setjmp.h> #include <syslog.h> #include <unistd.h> #define SIZE20 20 extern volatile sig_atomic_t e_flag; void display_info(const char *info) { if (info) { (void)fputs(info, stderr); } } void sig_handler1(int signum) { int s0 = signum; e_flag = 1; } int func(void) { e_flag = 0; if (signal(SIGINT, sig_handler1) == SIG_ERR) { /* Handle error */ } char *info = (char *)calloc(SIZE20, 1); if (info == NULL) { /* Handle error */ } while (!e_flag) { /* Main loop program code */ display_info(info); /* More program code */ } free(info); info = NULL; return 0; }
Решимость: Undecidable |
[1] Выдержки из стандарта «Техническая спецификация ISO/IEC TS 17961 - 2013-11-15» воспроизводятся с согласия АФНОР. Только оригинальный и полный текст стандарта, опубликованный AFNOR Editions - доступный через веб-сайт www.boutique.afnor.org - имеет нормативное значение.
1. Если смысл перевода понятен, то лучше оставьте как есть и не придирайтесь к словам, синонимам и тому подобному. О вкусах не спорим.
2. Не дополняйте перевод комментариями “от себя”. В исправлении не должно появляться дополнительных смыслов и комментариев, отсутствующих в оригинале. Такие правки не получится интегрировать в алгоритме автоматического перевода.
3. Сохраняйте структуру оригинального текста - например, не разбивайте одно предложение на два.
4. Не имеет смысла однотипное исправление перевода какого-то термина во всех предложениях. Исправляйте только в одном месте. Когда Вашу правку одобрят, это исправление будет алгоритмически распространено и на другие части документации.
5. По иным вопросам, например если надо исправить заблокированное для перевода слово, обратитесь к редакторам через форму технической поддержки.