Чтение онлайн

на главную

Жанры

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

Мы вернемся к проблеме повторного вхождения в главе 26 и увидим, как проблема с переменной

errno
решается с помощью потоков. В следующем разделе описываются некоторые версии функций имен узлов, допускающие повторное вхождение.

11.19. Функции gethostbyname_r и gethostbyaddr_r

Чтобы превратить функцию, не допускающую повторное вхождение, такую как

gethostbyname
, в повторно входимую, можно воспользоваться двумя способами.

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

gethostbyname
(которая не допускает повторное вхождение) к функции
gethostbyname_r
(которая допускает повторное вхождение). Но это решение усложняется, поскольку помимо того, что вызывающий процесс должен предоставить структуру
hostent
для заполнения, эта структура также указывает на другую информацию: каноническое имя, массив указателей на псевдонимы, строки псевдонимов, массив указателей на адреса и сами адреса (см., например, рис. 11.2). Вызывающий процесс должен предоставить один большой буфер, используемый для дополнительной информации, и заполняемая структура
hostent
будет содержать различные указатели на этот буфер. При этом добавляется как минимум три аргумента функции: указатель на заполняемую структуру
hostent
, указатель на буфер, используемый для всей прочей информации, и размер этого буфера. Требуется также четвертый дополнительный аргумент — указатель на целое число, в котором будет храниться код ошибки, поскольку глобальная целочисленная переменная
h_errno
больше не может использоваться. (Глобальная целочисленная переменная
h_errno
создает ту же проблему повторного вхождения, которая описана нами для переменной
errno
.)

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

Медиум

Злобин Михаил
1. О чем молчат могилы
Фантастика:
фэнтези
7.90
рейтинг книги
Медиум

Жена на четверых

Кожина Ксения
Любовные романы:
любовно-фантастические романы
эро литература
5.60
рейтинг книги
Жена на четверых

Великий род

Сай Ярослав
3. Медорфенов
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Великий род

Дурная жена неверного дракона

Ганова Алиса
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Дурная жена неверного дракона

Черный маг императора

Герда Александр
1. Черный маг императора
Фантастика:
юмористическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Черный маг императора

Приручитель женщин-монстров. Том 5

Дорничев Дмитрий
5. Покемоны? Какие покемоны?
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Приручитель женщин-монстров. Том 5

Барон ненавидит правила

Ренгач Евгений
8. Закон сильного
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Барон ненавидит правила

Приручитель женщин-монстров. Том 14

Дорничев Дмитрий
14. Покемоны? Какие покемоны?
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Приручитель женщин-монстров. Том 14

Совершенный: Призрак

Vector
2. Совершенный
Фантастика:
боевая фантастика
рпг
5.00
рейтинг книги
Совершенный: Призрак

Покоривший СТЕНУ. Десятый этаж

Мантикор Артемис
3. Покоривший СТЕНУ
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Покоривший СТЕНУ. Десятый этаж

Книга пятая: Древний

Злобин Михаил
5. О чем молчат могилы
Фантастика:
фэнтези
городское фэнтези
мистика
7.68
рейтинг книги
Книга пятая: Древний

Последний попаданец

Зубов Константин
1. Последний попаданец
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Последний попаданец

Разведчик. Заброшенный в 43-й

Корчевский Юрий Григорьевич
Героическая фантастика
Фантастика:
боевая фантастика
попаданцы
альтернативная история
5.93
рейтинг книги
Разведчик. Заброшенный в 43-й

Её (мой) ребенок

Рам Янка
Любовные романы:
современные любовные романы
6.91
рейтинг книги
Её (мой) ребенок