C: "Нет такого файла или каталога" в sem_open с O_CREAT и правильным именем семафора

Я пытаюсь создать семафоры в функции инициализации в C, как это:

void sem_init(int size, sem_t** sem1, sem_t** sem2) {
  char* semname1 = "/somename";
  char* semname2 = "/someothername";

  errno = 0;
  *sem1 = sem_open(semname1, O_CREAT, S_IRUSR|S_IWUSR, 0);
  printf(strerror(errno));

  errno = 0;
  *sem2 = sem_open(semname2, O_CREAT, S_IRUSR|S_IWUSR, size);
  printf(strerror(errno));
}

Но даже несмотря на то, что я установил флаг O_CREAT и имена well_formed, я всегда получаю "Нет такого файла или каталога" в качестве вывода. Семафоры создаются в /dev/shm/...

Я не вижу очевидной причины возникновения ошибки. Пожалуйста, помогите мне в том, что я делаю неправильно.

Заранее благодарны за Вашу помощь.

2 ответа

Как указывалось в комментариях к вопросу о ФП, неверное значение в errno используется. Предложить:

void sem_init(int size, sem_t** sem1, sem_t** sem2) {
    char* semname1 = "/somename";
    char* semname2 = "/someothername";
    sem_t local_sem1;
    sem_t local_sem2;

    if( (local_sem1 = sem_open(semname1, O_CREAT, S_IRUSR|S_IWUSR, 0) ) == SEM_FAILED )
    {
        perror( "sem_open for sem1 failed" );
        exit( EXIT_FAILURE );
    }

    *sem1 = local_sem1;

    if( (local_sem2 = sem_open(semname2, O_CREAT, S_IRUSR|S_IWUSR, 0) ) == SEM_FAILED )
    {
        perror( "sem_open doe awm2 failed" );
        exit( EXIT_FAILURE );
    }

    *sem2 = local_sem2;
}

Как сообщалось в комментариях и предыдущих ответах, errno не определено после вызова службы, если последний не вернулся с ошибкой (например, -1 или SEM_FAILED или MAP_FAILED в зависимости от службы). Причина заключается в том, что служба может вызывать несколько подслужб, которые могут временно выйти из строя и привести к установке некоторых значений для параметра errno , но это не приведет к сбою самой службы.

Например, внутренне создает временный файл в /dev/shm. Для этого он генерирует случайное имя благодаряуслуга. Но сгенерированное имя может уже существовать. Итак, попытка создания файла сделаетвернуть ЕСТЬ . Следовательно, исходный код делает несколько попыток генерации случайных имен файлов, пока создание не завершится успешно. Таким образом, после успешного создания errno может по-прежнему содержать EEXIST , но возвращаемый код изв порядке (т.е. отличается от SEM_FAILED). Вот фрагмент кода, который делает все эти попытки (glibc-2.34, файл sysdeps/pthread/sem_open.c):

      #define NRETRIES 50
      while (1)
    {
      /* We really want to use mktemp here.  We cannot use mkstemp
         since the file must be opened with a specific mode.  The
         mode cannot later be set since then we cannot apply the
         file create mask.  */
      if (__mktemp (tmpfname) == NULL)
        {
          result = SEM_FAILED;
          goto out;
        }

      /* Open the file.  Make sure we do not overwrite anything.  */
      fd = __open (tmpfname, O_RDWR | O_CREAT | O_EXCL, mode);
      if (fd == -1)
        {
          if (errno == EEXIST)
        {
          if (++retries < NRETRIES)
            {
              /* Restore the six placeholder bytes before the
             null terminator before the next attempt.  */
              memcpy (tmpfname + sizeof (tmpfname) - 7, "XXXXXX", 6);
              continue;
            }

          __set_errno (EAGAIN);
        }

          result = SEM_FAILED;
          goto out;
        }

      /* We got a file.  */
      break;
    }

В случае использования OP errno равно ENOENT , а служба возвращает значение, отличное от SEM_FAILED . На самом деле сервис понимает, что файл для создания уже существует. Поскольку флаг O_EXCL не передается, считается, что все в порядке. Таким образом, файл удаляется, и снова предпринимается попытка открытия, чтобы убедиться, что получен ENOENT перед повторным созданием файла. Вот фрагмент кода той же функции для этого варианта использования:

      [...]
    try_again:
      fd = __open (dirname.name,
           (oflag & ~(O_CREAT|O_ACCMODE)) | O_NOFOLLOW | O_RDWR);

      if (fd == -1)
        {
          /* If we are supposed to create the file try this next.  */
          if ((oflag & O_CREAT) != 0 && errno == ENOENT)
            goto try_create;

          /* Return.  errno is already set.  */
        }
      else
        /* Check whether we already have this semaphore mapped and
           create one if necessary.  */
        result = __sem_check_add_mapping (name, fd, SEM_FAILED);
[...]
      if ((oflag & O_EXCL) == 0 && errno == EEXIST)
        {
          /* Remove the file.  */
          __unlink (tmpfname);

          /* Close the file.  */
          __close (fd);

          goto try_again;
        }
[...]
Другие вопросы по тегам