Функция sem_open
Функция sem_open
В листинге 10.22 приведен текст функции sem_open, которая создает новый семафор или открывает существующий.
Листинг 10.22. Функция sem_open
//my_pxsem_fifo/sem_open.с
1 #include "unpipc.h"
2 #include "semaphore.h"
3 #include <stdarg.h> /* для произвольного списка аргументов */
4 mysem_t *
5 mysem_open(const char *pathname, int oflag, …)
6 {
7 int i, flags, save_errno;
8 char c;
9 mode_t mode;
10 va_list ap;
11 mysem_t *sem;
12 unsigned int value;
13 if (oflag & O_CREAT) {
14 va_start(ap, oflag); /* ар инициализируется последним аргументом */
15 mode = va_arg(ap, va_mode_t);
16 value = va_arg(ap, unsigned int);
17 va_end(ap);
18 if (mkfifo(pathname, mode) < 0) {
19 if (errno == EEXIST && (oflag & O_EXCL) == 0)
20 oflag &= ~O_CREAT; /* уже существует, OK */
21 else
22 return(SEM_FAILED);
23 }
24 }
25 if ((sem = malloc(sizeof(mysem_t))) == NULL)
26 return(SEM_FAILED);
27 sem->sem_fd[0] = sem->sem_fd[1] = –1;
28 if ((sem->sem_fd[0] = open(pathname, O_RDONLY | O_NONBLOCK)) < 0)
29 goto error;
30 if ((sem->sem_fd[1] = open(pathname, O_WRONLY | O_NONBLOCK)) < 0)
31 goto error;
32 /* отключение неблокируемого режима для sem_fd[0] */
33 if ((flags = fcntl(sem->sem_fd[0], F_GETFL, 0)) < 0)
34 goto error;
35 flags &= ~O_NONBLOCK;
36 if (fcntl(sem->sem_fd[0], F_SETFL, flags) < 0)
37 goto error;
38 if (oflag & O_CREAT) { /* инициализация семафора */
39 for (i = 0; i < value; i++)
40 if (write(sem->sem_fd[1], &c, 1) != 1)
41 goto error;
42 }
43 sem->sem_magic = SEM_MAGIC;
44 return(sem);
45 error:
46 save_errno = errno;
47 if (oflag & O_CREAT)
48 unlink(pathname); /* если мы создали FIFO */
49 close(sem->sem_fd[0]); /* игнорируем ошибку */
50 close(sem->sem_fd[1]); /* игнорируем ошибку */
51 free(sem);
52 errno = save_errno;
53 return(SEM_FAILED);
54 }
Создание нового sсемафора
13-17 Если при вызове указан флаг O_CREAT, должно быть указано четыре аргумента, а не два. Мы вызываем va_start, после чего переменная ар указывает на последний явно указанный аргумент (oflag). Затем мы используем ар и функцию va_arg для получения значений третьего и четвертого аргументов. Работу со списком аргументов переменной длины и использование нашего типа va_mode_t мы обсуждали в связи с листингом 5.17.
Создание нового канала FIFO
18-23 Создается новый канал FIFO, имя которого было указано при вызове функции. Как мы отмечали в разделе 4.6, эта функция возвращает ошибку EEXIST, если канал уже существует. Если при вызове sem_open флаг O_EXCL не был указан, мы пропускаем эту ошибку; но нам не нужно будет инициализировать этот канал, так что мы при этом сбрасываем флаг O_CREAT.
Выделение памяти под тип sem_t и открытие FIFO на чтение и запись
25-37 Мы выделяем место для типа sem_t, который содержит два дескриптора. Затем мы дважды открываем канал FIFO: один раз только на чтение, а другой — только на запись. При этом мы не хотим блокирования при вызове open, поэтому указываем флаги O_NONBLOCK при открытии очереди только для чтения (вспомните табл. 4.1). Мы также указываем флаг O_NONBLOCK при открытии канала на запись, но это предназначено для обнаружения переполнения (на тот случай, если мы попытаемся записать больше, чем позволяет PIPE_BUF). После открытия канала мы отключаем неблокируемый режим для дескриптора, открытого на чтение.
Инициализация значения созданного семафора
38-42 Если мы создали семафор, его нужно проинициализировать, записав в канал FIFO value байтов. Если указанное при вызове значение value превышает определенное реализацией ограничение PIPE_BUF, вызов write после переполнения FIFO вернет ошибку с кодом EAGAIN.
Данный текст является ознакомительным фрагментом.