2. Установка обработчика сигнала SIGINT (генерируется при нажатии Ctrl+C). Обработчик вызывает функцию crypt() для зашифровки строки текста, предоставленной в качестве второго аргумента.

3. Вход в бесконечный цикл for, в котором используется функция crypt() для зашифровки строки текста в первом аргументе командной строки и осуществление проверки того, что возвращенная строка совпадает со строкой, сохраненной при выполнении шага 1.

Строки в шаге 3 всегда будут совпадать при отсутствии сигнала. Другое дело, если поступает сигнал SIGINT и выполнение обработчика прерывает выполнение основной программы сразу же после вызова функции crypt() в цикле for и перед осуществлением проверки совпадения строк. В этом случае программа сообщит о несовпадении. При запуске программы мы увидим следующее:

$ ./non_reentrant abc def

Несколько раз нажимать Ctrl-C для генерации SIGINT

Mismatch on call 109871 (mismatch=1 handled=1)

Mismatch on call 128061 (mismatch=2 handled=2)

Многие строки вывода были удалены

Mismatch on call 727935 (mismatch=149 handled=156)

Mismatch on call 729547 (mismatch=150 handled=157)

Нажать Ctrl-\ для генерации SIGQUIT

Quit (core dumped)

Если мы сравним значения mismatch и handled в вышеприведенном выводе, то увидим, что в большинстве случаев при инициализации сигнала происходит перезапись статически выделенного буфера между вызовом функции crypt() и сравнением строк в main().

Листинг 21.1. Вызов нереентерабельной функции из main() и обработчика сигнала

signals/nonreentrant.c

#define _XOPEN_SOURCE 600

#include

#include

#include

#include "tlpi_hdr.h"

static char *str2; /* Устанавливается из argv[2] */

static int handled = 0; /* Счетчик вызовов обработчика */

static void

handler(int sig)

{

crypt(str2, "xx");

handled++;

}

int

main(int argc, char *argv[])

{

char *cr1;

int callNum, mismatch;

struct sigaction sa;

if (argc!= 3)

usageErr("%s str1 str2\n", argv[0]);

str2 = argv[2]; /* Сделать argv[2] доступным обработчику */

cr1 = strdup(crypt(argv[1], "xx")); /* Скопировать статически

выделенную строку в иной буфер */

if (cr1 == NULL)

errExit("strdup");

sigemptyset(&sa.sa_mask);

sa.sa_flags = 0;

sa.sa_handler = handler;

if (sigaction(SIGINT, &sa, NULL) == –1)

errExit("sigaction");

/* Многократно вызывать crypt() с использованием argv[1]. Если прервано

обработчиком сигнала, то статическое хранилище, возвращенное crypt(),

будет перезаписано результатами зашифровки argv[2], а strcmp()

обнаружит несовпадение со значением 'cr1'. */

for (callNum = 1, mismatch = 0;; callNum++) {

if (strcmp(crypt(argv[1], "xx"), cr1)!= 0) {

mismatch++;

printf("Mismatch on call %d (mismatch=%d handled=%d)\n",

callNum, mismatch, handled);

}

}

}

signals/nonreentrant.c

Стандартные функции, безопасные для асинхронных сигналов

Функция, безопасная для асинхронных сигналов, — это такая функция, реализация которой гарантирует безопасность при вызове из обработчика. Функция может быть безопасной для асинхронного сигнала либо благодаря тому, что она реентерабельна, либо потому, что она непрерываема обработчиком.

Безопасность перечисленных в табл. 21.1 функций для асинхронных сигналов требуется различными стандартами. Если после имени в таблице не указано v2 или v3, то требование безопасности функции для асинхронных сигналов установлено стандартом POSIX.1-1990. В стандарт SUSv2 были добавлены функции, помеченные в таблице v2, а функции с отметкой v3 были включены в стандарт SUSv3. В отдельных реализациях UNIX могут встречаться и другие функции, безопасные для асинхронных сигналов, однако все реализации UNIX, соответствующие стандарту, должны гарантировать, что как минимум функции, приведенные в таблице, являются безопасными для асинхронных сигналов (если присутствуют в реализации: не все из перечисленных функций реализованы в Linux).

Таблица 21.1. Функции, которые должны быть безопасными для асинхронных сигналов согласно стандартам POSIX.1-1990, SUSv2 и SUSv3

_Exit() (v3)

_exit()

abort() (v3)

accept() (v3)

access()

aio_error() (v2)

aio_return() (v2)

aio_suspend() (v2)

alarm()

bind() (v3)

cfgetispeed()

cfgetospeed()

cfsetispeed()

cfsetospeed()

chdir()

chmod()

chown()

clock_gettime() (v2)

close()

connect() (v3)

getpid()

getppid()

getsockname() (v3)

getsockopt() (v3)

getuid()

kill()

link()

listen() (v3)

lseek()

lstat() (v3)

mkdir()

mkfifo()

open()

pathconf()

pause()

pipe()

poll() (v3)

posix_trace_event() (v3)

pselect() (v3)

raise() (v2)

sigdelset()

sigemptyset()

sigfillset()

sigismember()

signal() (v2)

sigpause() (v2)

sigpending()

sigprocmask()

sigqueue() (v2)

sigset() (v2)

sigsuspend()

sleep()

socket() (v3)

sockatmark() (v3)

socketpair() (v3)

stat()

symlink() (v3)

sysconf()

tcdrain()

tcflow()

creat()

dup()

dup2()

execle()

execve()

fchmod() (v3)

fchown() (v3)

fcntl()

fdatasync() (v2)

fork()

fpathconf() (v2)

fstat()

fsync() (v2)

ftruncate() (v3)

getegid()

Перейти на страницу:

Похожие книги