Вход/Регистрация
UNIX: разработка сетевых приложений
вернуться

Стивенс Уильям Ричард

Шрифт:

В качестве альтернативы некоторые реализации с поддержкой программных потоков (Digital Unix 4.0 и HP_UX 10.30) предоставляют версии этих функций, допускающие повторное вхождение за счет использования собственных данных программных потоков.

Функции

inet_pton
и
inet_ntop
всегда допускают повторное вхождение.

Исторически функция

inet_ntoa
не допускает повторное вхождение, но некоторые реализации с поддержкой потоков предоставляют версию, допускающую повторное вхождение, которая строится на основе собственных данных потоков.

Функция

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

Функция

getnameinfo
допускает повторное вхождение, только если она сама вызывает такие функции, то есть если она вызывает соответствующую версию функции
gethostbyaddr
для получения имени узла или функции
getservbyport
для получения имени службы. Обратите внимание, что обе результирующих строки (для имени узла и для имени службы) размещаются в памяти вызывающим процессом, чтобы обеспечить возможность повторного вхождения.

Похожая проблема возникает с переменной

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

поместить аргумент системного вызова (целочисленный дескриптор) в регистр;

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

close
;

активизировать системный вызов (переключиться на ядро со специальной инструкцией);

проверить значение регистра, чтобы увидеть, что произошла ошибка;

если ошибки нет, возвратить (0);

сохранить значение какого-то другого регистра в переменной

errno
;

возвратить (-1).

Прежде всего заметим, что если ошибки не происходит, значение переменной

errno
не изменяется. Поэтому мы не можем посмотреть значение этой переменной, пока мы не узнаем, что произошла ошибка (обычно на это указывает возвращаемое функцией значение -1).

Будем считать, что программа проверяет возвращаемое значение функции

close
и затем выводит значение переменной
errno
, если произошла ошибка, как в следующем примере:

if (close(fd) < 0) {

fprintf(stderr, "close error, errno = $d\n", errno);

exit(1);

}

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

errno
. Если, например, при вызове обработчика сигналов главный поток управления находится между
close
и
fprintf
и обработчик сигналов делает какой-то другой системный вызов, возвращающий ошибку (допустим, вызывается функция
write
), то значение переменной
errno
, записанное при вызове функции
close
, заменяется на значение, записанное при вызове функции
write
.

При рассмотрении этих двух проблем в связи с обработчиками сигналов одним из решений проблемы с функцией

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

void sig_alrm(int signo) {

int errno_save;

errno_save = errno; /* сохраняем значение этой переменной

при вхождении */

if (write( ... ) != nbytes)

fprintf(stderr, "write error, errno = %d\n", errno);

errno = errno_save; /* восстанавливаем значение этой переменной

при завершении */

}

В этом коде мы также вызываем функцию

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

  • Читать дальше
  • 1
  • ...
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • ...

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

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

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

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