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

на главную - закладки

Жанры

UNIX: взаимодействие процессов

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

Шрифт:

Функция mq_open

В листинге 5.17 приведен текст первой части функции mq_open, создающей новую очередь сообщений или открывающей существующую.

Листинг 5.17. Функция mq_open: первая часть

//my_pxmsg._mmap/mq_open. с

1 #include "unpipc.h"

2 #include "mqueue.h"

3 #include <stdarg.h>

4 #define MAX_TRIES 10

5 struct mymq_attr defattr =

6 { 0, 128, 1024, 0 };

7 mymqd_t

8 mymq_open(const char *pathname, int oflag, …)

9 {

10 int i, fd, nonblock, created, save_errno;

11 long msgsize, filesize, index;

12 va_list ap;

13 mode_t mode;

14 int8_t *mptr;

15 struct stat statbuff;

16 struct mymq_hdr *mqhdr;

17 struct mymsg_hdr *msghdr;

18 struct mymq_attr *attr;

19 struct mymq_info *mqinfo;

20 pthread_mutexattr_t mattr;

21 pthread_condattr_t cattr;

22 created = 0;

23 nonblock = oflag & O_NONBLOCK;

24 oflag &= ~O_NONBLOCK;

25 mptr = (int8_t *) MAP_FAILED;

26 mqinfo = NULL;

27 again:

28 if (oflag & O_CREAT) {

29 va_start(ap, oflag); /* ар инициализируется последним аргументом */

30 mode = va_arg(ap, va_mode_t) & ~S_IXUSR;

31 attr = va_arg(ap, struct mymq_attr *);

32 va_end(ap);

33 /* открытие с установкой бита user-execute */

34 fd = open (pathname, oflag | O_EXCL | O_RDWR, mode | S_IXUSR);

35 if (fd < 0) {

36 if (errno == EEXIST && (oflag & O_EXCL) == 0)

37 goto exists; /* уже существует, OK */

38 else

39 return((mymqd_t) –1);

40 }

41 created = 1;

42 /* при создании файла он инициализируется */

43 if (attr == NULL)

44 attr = &defattr;

45 else {

46 if (attr->mq_maxmsg <– 0 || attr->mq_msgsize <= 0) {

47 errno = EINVAL;

48 goto err;

49 }

50 }

Обработка списка аргументов переменного размера

29-32 Функция может быть вызвана либо с двумя, либо с четырьмя аргументами в зависимости от того, указан ли флаг O_CREAT. Если флаг указан, третий аргумент имеет тип mode_t, а это простой системный тип, являющийся одним из целых типов. При этом мы столкнемся с проблемой в BSD/OS, где этот тип данных определен как unsigned short (16 бит). Поскольку целое в этой реализации занимает 32 бита, компилятор С увеличивает аргумент этого типа с 16 до 32 бит, потому что все короткие целые в списке аргументов увеличиваются до обычных целых. Но если мы укажем mode_t при вызове va_arg, он пропустит 16 бит аргумента в стеке, если этот аргумент был увеличен до 32 бит. Следовательно, мы должны определить свой собственный тип данных, va_mode_t, который будет целым в BSD/OS и типом mode_t в других системах. Эту проблему с переносимостью решают приведенные ниже строки нашего заголовка unpipc.h (листинг В.1):

#ifdef __bsdi__

#define va_mode_t int

#else

#define va_mode_t mode_t

#endif

30 Мы сбрасываем бит user-execute (S_IXUSR) в переменной mode по причинам, которые будут вскоре раскрыты.

Создание новой очереди сообщений

33-34 Создается обычный файл с именем, указанным при вызове функции, и устанавливается бит user-execute. 

Обработка потенциальной ситуации гонок

35-40 Если бы при указании флага O_CREAT мы просто открыли файл, отобразили его содержимое в память и проинициализировали отображенный файл (как будет описано ниже), у нас возникла бы ситуация гонок. Очередь сообщений инициализируется mq_open только в том случае, если вызывающий процесс указывает флаг O_CREAT и очередь сообщений еще не существует. Это означает, что нам нужно каким-то образом определять, существует она или нет. Для этого при открытии файла для последующего отображения в память мы всегда указываем флаг O_EXCL. Возвращение ошибки EEXIST функцией open является ошибкой для mq_open только в том случае, если при вызове был указан флаг O_EXCL. В противном случае при возвращении функцией open ошибки EEXIST мы делаем вывод, что файл уже существует, и переходим к листингу 5.19, как если бы флаг O_CREAT вовсе не был указан.

Ситуация гонок может возникнуть потому, что использование отображаемого в память файла для реализации очереди сообщений требует двух шагов при инициализации очереди: сначала файл должен быть создан функцией open, а затем его содержимое должно быть проинициализировано. Проблема возникает, если два потока (одного или различных процессов) вызывают mq_open приблизительно одновременно. Один из потоков может создать файл, после чего управление будет передано системой второму потоку, прежде чем первый завершит инициализацию файла. Второй поток обнаружит, что файл уже существует (вызвав open с флагом O_EXCL), и приступит к использованию очереди сообщений.

Мы используем бит user-execute для указания того, был ли проинициализирован файл с очередью сообщений. Этот бит устанавливается только тем потоком, который создает этот файл (флаг O_EXCL позволяет определить этот поток); этот поток инициализирует файл с очередью сообщений, а затем сбрасывает бит user-execute.

Аналогичная ситуация может возникнуть в листингах 10.28 и 10.37.

Проверка атрибутов

42-50 Если при вызове в качестве последнего аргумента передан нулевой указатель, очередь сообщений инициализируется со значениями атрибутов по умолчанию: 128 сообщений в очереди и 1024 байта на сообщение. Если атрибуты указаны явно, мы проверяем, что mq_maxmsg и mq_msgsize имеют положительные значения.

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

Рассвет русского царства 3

Грехов Тимофей
3. Новая Русь
Фантастика:
историческое фэнтези
альтернативная история
5.00
рейтинг книги
Рассвет русского царства 3

П 2

Дронт Николай
2. Придворный
Фантастика:
фэнтези
героическая фантастика
5.00
рейтинг книги
П 2

Язычник

Мазин Александр Владимирович
5. Варяг
Приключения:
исторические приключения
8.91
рейтинг книги
Язычник

Гримуар темного лорда VI

Грехов Тимофей
6. Гримуар темного лорда
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Гримуар темного лорда VI

Шайтан Иван 6

Тен Эдуард
6. Шайтан Иван
Фантастика:
попаданцы
альтернативная история
историческое фэнтези
7.00
рейтинг книги
Шайтан Иван 6

Законы Рода. Том 4

Мельник Андрей
4. Граф Берестьев
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 4

Портрет дьявола: Собрание мистических рассказов

Скотт Вальтер
Проза:
классическая проза
8.09
рейтинг книги
Портрет дьявола: Собрание мистических рассказов

Пересмешник

Пехов Алексей Юрьевич
Фантастика:
фэнтези
9.38
рейтинг книги
Пересмешник

Князь Целитель 5

Ткачев Андрей Юрьевич
5. Князь Целитель
Фантастика:
боевая фантастика
городское фэнтези
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Князь Целитель 5

Барон. Книга вторая

Первухин Андрей Евгеньевич
6. Ученик
Фантастика:
фэнтези
попаданцы
5.40
рейтинг книги
Барон. Книга вторая

Гром Раскатного. Том 1

Володин Григорий Григорьевич
1. Штормовой Предел
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Гром Раскатного. Том 1

Потомок бога 3

Решетов Евгений Валерьевич
3. Локки
Фантастика:
аниме
фэнтези
5.00
рейтинг книги
Потомок бога 3

Газлайтер. Том 8

Володин Григорий
8. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 8

Дракон

Бубела Олег Николаевич
5. Совсем не герой
Фантастика:
фэнтези
попаданцы
9.31
рейтинг книги
Дракон