Вызов функций в стандартной библиотеке C, отличных от прерывания, _Exit и сигнала из обработчика сигнала
Вызов функций в стандартной библиотеке C, отличных от прерывания, _Exit и сигнала из обработчика сигнала. [1 ]
Эта проверка проверяет наличие следующих проблем:
Функция, вызываемая из обработчика сигнала, не является асинхронно-безопасной (строгой).
Функция, вызванная из обработчика сигнала, не является асинхронно-безопасной.
Функция, вызываемая из обработчика сигнала, не является асинхронно-безопасной (strict), возникает, когда обработчик сигнала вызывает функцию, которая не является асинхронно-безопасной согласно стандарту C. Асинхронно-безопасная функция может быть прервана в любой момент ее выполнения, затем вызвана снова, не вызывая противоречивого состояния. Он также может правильно обрабатывать глобальные данные, которые могут находиться в несогласованном состоянии.
При выборе функции checker, вызываемой из обработчика сигналов, которая не является асинхронно-безопасной, программа checker обнаруживает вызовы функций, которые не являются асинхронно-безопасными в соответствии со стандартом 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 имеет тип volatile 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;
} | Разрешимость: неразрешимая |
[1] Выдержки из стандарта «ISO/IEC TS 17961 Technical Specification - 2013-11-15» воспроизводятся с согласия AFNOR. Нормативную ценность имеет только оригинальный и полный текст стандарта, опубликованный изданиями AFNOR - доступный через веб-сайт www.boutique.afnor.org.
1. Если смысл перевода понятен, то лучше оставьте как есть и не придирайтесь к словам, синонимам и тому подобному. О вкусах не спорим.
2. Не дополняйте перевод комментариями “от себя”. В исправлении не должно появляться дополнительных смыслов и комментариев, отсутствующих в оригинале. Такие правки не получится интегрировать в алгоритме автоматического перевода.
3. Сохраняйте структуру оригинального текста - например, не разбивайте одно предложение на два.
4. Не имеет смысла однотипное исправление перевода какого-то термина во всех предложениях. Исправляйте только в одном месте. Когда Вашу правку одобрят, это исправление будет алгоритмически распространено и на другие части документации.
5. По иным вопросам, например если надо исправить заблокированное для перевода слово, обратитесь к редакторам через форму технической поддержки.