Публикация в семафор POSIX с использованием JNA - PullRequest
1 голос
/ 09 июля 2019

Я пытаюсь отправить сообщение на семафор, используя JNA на компьютере с Linux.По какой-то причине я всегда получаю ошибку 22 (неверный аргумент) даже для этого простого примера.В моем понимании, должен ли приведенный ниже код не открывать семафор POSIX, публиковать и закрывать его снова?

public class Sample {

  private static final int O_CREAT = 0x40;

  public static void main(String[] args) throws Exception {
    File notifier = new File("/tmp", "_test" + new Random().nextInt());
      if (!notifier.isFile() && !notifier.createNewFile()) {
        throw new IllegalStateException("Could not create notifier: " + notifier);
      }

      SempahoreLibrary library = Native.load("c", SempahoreLibrary.class);
      Pointer semaphore = library.sem_open(notifier.getAbsolutePath(), O_CREAT, 666, 0);
      try {
        library.sem_post(semaphore);
      } finally {
        library.sem_close(semaphore);
      }
  }

  interface SempahoreLibrary extends Library {
    Pointer sem_open(String name, int flags, int mode, int value) throws LastErrorException;
    int sem_post(Pointer pointer) throws LastErrorException;
    int sem_close(Pointer pointer) throws LastErrorException;
  }
}

1 Ответ

1 голос
/ 10 июля 2019

Сначала я тоже не мог заставить его работать с JNR (настоятельно рекомендуется через JNA), и мне стало любопытно. Запись в C помогла ..:)

Strace на порту C дал понять, что вам не нужно создавать файл заранее и затем «сопоставьте» семафор с ним. Также использование полного пути неверно, потому что семафоры создаются в / dev / shm и "/" в винтах пути до всего:

futex(0x7f731b1190d0, FUTEX_WAKE_PRIVATE, 2147483647) = 0
openat(AT_FDCWD, "/dev/shm/sem.sema", O_RDWR|O_NOFOLLOW) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=32, ...}) = 0

Таким образом, вы должны иметь возможность удалить весь файл / путь создания и просто использовать обычное имя без пути для семафора в sem_open. Также режим файла должен быть восьмеричным, и вы также должны загрузить библиотеку pthread - это необходимо.

Вот рабочий пример на C:

// clang -Wall sema.c -lpthread

#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main(int argc, char** argv)
{
    sem_t* s = sem_open("notifier", O_CREAT, 0644, 0);

    if (!s) {
        perror("sem_open");
        exit(errno);
    }

    printf("s: %p\n", s);

    sem_post(s);

    int value = -1;
    sem_getvalue(s, &value);
    printf("value: %d\n", value);

    sem_wait(s);
    sem_getvalue(s, &value);
    printf("value: %d\n", value);

    sem_close(s);

    exit(EXIT_SUCCESS);
}

Вот рабочая версия Java с использованием JNR:

import jnr.ffi.LastError;
import jnr.ffi.LibraryLoader;
import jnr.ffi.Pointer;
import jnr.ffi.Runtime;

public class Semaphore
{
    private static final int O_CREAT = 0x40;

    public interface SempahoreLibrary
    {
        Pointer sem_open(String name, int flags, int mode, int value);
        int sem_post(Pointer pointer);
        int sem_close(Pointer pointer);
    }

    public static void main(String[] args) throws Exception
    {

        LibraryLoader<SempahoreLibrary> loader = LibraryLoader.create(SempahoreLibrary.class);
        loader.library("c");
        loader.library("pthread");

        SempahoreLibrary library = loader.load();
        jnr.ffi.Runtime runtime = Runtime.getRuntime(library);

        Pointer semaphore = library.sem_open("notifier", O_CREAT, 0644, 0);
        if (semaphore == null)
        {
            int errno = LastError.getLastError(runtime);
            System.out.println("sem_open: " + errno);
            System.exit(errno);
        }

        System.out.println("semaphore: " + Long.toHexString(semaphore.address()));

        try
        {
            int error = library.sem_post(semaphore);
            System.out.println("post: " + (error == 0 ? "OK" : LastError.getLastError(runtime)));
        }
        finally
        {
            int error = library.sem_close(semaphore);
            System.out.println("close: " + (error == 0 ? "OK" : LastError.getLastError(runtime)));
        }
    }
}
...