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

Функция 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.

Оглавление книги


Генерация: 0.703. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз