Системные вызовы, допускающие повторный запуск — КиберПедия 

Адаптации растений и животных к жизни в горах: Большое значение для жизни организмов в горах имеют степень расчленения, крутизна и экспозиционные различия склонов...

Типы сооружений для обработки осадков: Септиками называются сооружения, в которых одновременно происходят осветление сточной жидкости...

Системные вызовы, допускающие повторный запуск

2021-01-29 65
Системные вызовы, допускающие повторный запуск 0.00 из 5.00 0 оценок
Заказать работу

 

Значение для (см. раздел 4.3 «Определение ошибок») указывает, что системный вызов был прерван. Хотя с этим значением ошибки может завершаться большое количество системных вызовов, двумя наиболее значительными являются и. Рассмотрите следующий код:

 

 

Предположим, что система успешно прочла (и заполнила) часть буфера, когда возник. Системный вызов еще не вернулся из ядра в программу, но ядро решает, что оно может доставить сигнал. Вызывается, запускается и возвращается в середину. Что возвратит?

В былые времена (V7, более ранние системы System V) возвратила бы ‑1 и установила бы равным. Не было способа сообщить, что данные были переданы. В данном случае V7 и System V действуют, как если бы ничего не случилось: не было перемещений данных в и из буфера пользователя, и смещение файла не было изменено. BSD 4.2 изменила это. Были два случая:

Медленные устройства

«Медленное устройство» является в сущности терминалом или почти всяким другим устройством, кроме обычного файла. В этом случае могла завершиться с ошибкой, лишь если не было передано никаких данных, когда появился сигнал. В противном случае системный вызов был бы запущен повторно, и возвратилась бы нормально.

Обычные файлы

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

Поведение BSD несомненно полезно; вы всегда можете сказать, сколько данных было прочитано.

Поведение POSIX сходно, но не идентично первоначальному поведению BSD. POSIX указывает, что [108] завершается с ошибкой лишь в случае появления сигнала до начала перемещения данных. Хотя POSIX ничего не говорит о «медленных устройствах», на практике это условие проявляется именно на них.

В противном случае, если сигнал прерывает частично выполненную, возвращенное значение является числом уже прочитанных байтов. По этой причине (а также для возможности обработки коротких файлов) всегда следует проверять возвращаемое значение и никогда не предполагать, что прочитано все запрошенное количество байтов. (Функция POSIX API, описанная позже, позволяет при желании получить поведение повторно вызываемых системных вызовов BSD.)

 

Пример: GNU Coreutils и

 

Для обработки случая EINTR в традиционных системах GNU Coreutils использует две функции, и. Код несколько запутан из‑за того, что один и тот же файл за счет включения #include и макросов реализует обе функции. Из файла в дистрибутиве Coreutils:

 

Строки 57–67 обрабатывают определения, создавая соответствующим образом и (см. ниже).

Строки 77–84 указывают на разновидность осложнений, возникающих при чтении. Здесь один особый вариант Unix не может обработать значения, превышающие, поэтому строки 83–84 выполняют сразу две операции: уменьшают значение числа, чтобы оно не превышало, и сохраняют его кратным 8192. Последняя операция служит эффективности дисковых операций: выполнение ввода/вывода с кратным основному размеру дискового блока объемом данных более эффективно, чем со случайными размерами данных. Как отмечено в комментарии, код сохраняет семантику и, где возвращенное число байтов может быть меньше затребованного.

Обратите внимание, что параметр может и в самом деле быть больше, поскольку count представляет тип, который является беззнаковым (unsigned). является чистым, который на всех современных системах является знаковым.

Строки 86–90 представляют действительный цикл, повторно осуществляющий операцию, пока она завершается ошибкой. Макрос не показан, но он обрабатывает случай в системах, на которых не определен. (Должен быть по крайней мере один такой случай, иначе код не будет возиться с установкой макроса; возможно, это было сделано для эмуляции Unix или POSIX в не‑Unix системе.) Вот:

 

 

В строке 18 определяет; это связано со строками 57–60 в.

 

Только GLIBC:

 

Файл <unistd.h> GLIBC определяет макрос TEMP_FAILURE_RETRY(), который вы можете использовать для инкапсулирования любого системного вызова, который может при неудачном вызове установить errno в EINTR. Его «объявление» следующее:

 

Вот определение макроса:

 

 

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

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

 

 

Состояния гонок и (ISO C)

 

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

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

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

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

 

 

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

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

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

 

 

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

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

 


Поделиться с друзьями:

Архитектура электронного правительства: Единая архитектура – это методологический подход при создании системы управления государства, который строится...

Состав сооружений: решетки и песколовки: Решетки – это первое устройство в схеме очистных сооружений. Они представляют...

Индивидуальные и групповые автопоилки: для животных. Схемы и конструкции...

Археология об основании Рима: Новые раскопки проясняют и такой острый дискуссионный вопрос, как дата самого возникновения Рима...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.015 с.