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

Данный текст является ознакомительным фрагментом.