Вход/Регистрация
Linux программирование в примерах
вернуться

Роббинс Арнольд

Шрифт:

установленным в EINTR. */

# define TEMP_FAILURE_RETRY(expression) \

 (__extension__ \

({ long int __result; \

do __result = (long int)(expression); \

while (__result == -1L && errno == EINTR); \

__result; }))

Макрос использует расширение GCC к языку С (как обозначено ключевым словом

__extension__
), которое допускает заключенным в фигурные скобки внутри обычных скобок выражениям возвращать значение, действуя таким образом подобно простому выражению.

Используя этот макрос, мы могли бы переписать

safe_read
следующим образом:

size_t safe_read(int fd, void const *buf, size_t count) {

 ssize_t result;

 /* Ограничить count, как в ранее приведенном комментарии. */

 if (count > INT_MAX)

count = INT_MAX & ~8191;

 result = TEMP_FAILURE_RETRY(read(fd, buf, count));

 return (size_t)result;

}

10.4.5. Состояния гонок и

sig_atomic_t
(ISO C)

Пока обработка одного сигнала за раз выглядит просто: установка обработчика сигнала в

main
и (не обязательная) переустановка самого себя обработчиком сигнала (или установка действия
SIG_IGN
) в качестве первого действия обработчика.

Но что произойдет, если возникнут два идентичных сигнала, один за другим? В частности, что, если ваша система восстановит действие по умолчанию для вашего сигнала, а второй сигнал появится после вызова обработчика, но до того, как он себя восстановит?

Или предположим, что вы используете

bsd_signal
, так что обработчик остается установленным, но второй сигнал отличается от первого? Обычно обработчику первого сигнала нужно завершить свою работу до того, как запускается второй, а каждый обработчик сигнала не должен временно игнорировать все прочие возможные сигналы!

Оба случая относятся к состоянию гонки. Одним решением для этих проблем является как можно большее упрощение обработчиков сигналов. Это можно сделать, создав флаговые переменные, указывающие на появление сигнала. Обработчик сигнала устанавливает переменную в true и возвращается. Затем основная логика проверяет флаговую переменную в стратегических местах:

int sig_int_flag = 0; /* обработчик сигнала устанавливает в true */

void int_handler(int signum) {

 sig_int_flag = 1;

}

int main(int argc, char **argv) {

 bsd_signal(SIGINT, int_handler);

 /* ...программа продолжается... */

 if (sig_int_flag) {

/* возник SIGINT, обработать его */

 }

 /* ...оставшаяся логика... */

}

(Обратите внимание, что эта стратегия уменьшает окно уязвимости, но не устраняет его).

Стандарт С вводит специальный тип —

sig_atomic_t
— для использования с такими флаговыми переменными. Идея, скрывающаяся за этим именем, в том, что присвоение значений переменным этого типа является атомарной операцией: т.е. они совершаются как одно делимое действие. Например, на большинстве машин присвоение значения
int
осуществляется атомарно, тогда как инициализация значений в структуре осуществляется либо путем копирования всех байтов в (сгенерированном компилятором) цикле, либо с помощью инструкции «блочного копирования», которая может быть прервана. Поскольку присвоение значения
sig_atomic_t
является атомарным, раз начавшись, оно завершается до того, как может появиться другой сигнал и прервать его.

Наличие особого типа является лишь частью истории. Переменные

sig_atomic_t
должны быть также объявлены как
volatile
:

volatile sig_atomic_t sig_int_flag = 0; /* обработчик сигнала устанавливает в true */

/* ...оставшаяся часть кода как раньше... */

Ключевое слово

volatile
сообщает компилятору, что переменная может быть изменена извне, за спиной компилятора, так сказать. Это не позволяет компилятору применить оптимизацию, которая могла бы в противном случае повлиять на правильность кода

Структурирование приложения исключительно вокруг переменных

sig_atomic_t
ненадежно. Правильный способ обращения с сигналами показан далее, в разделе 10.7 «Сигналы для межпроцессного взаимодействия».

10.4.6. Дополнительные предостережения

Стандарт POSIX предусматривает для обработчиков сигналов несколько предостережений:

• Что случается, когда возвращаются обработчики для

SIGFPE
,
SIGILL
,
SIGSEGV
или любых других сигналов, представляющих «вычислительные исключения», не определено.

  • Читать дальше
  • 1
  • ...
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: