StoryEdit 開発日誌

ウェブアプリ StoryEditを作ってましたが延期。普通のブログ。

JNAではまる。その3。 jna3からjna4、Direct mappingへ移行する。

はまりポイント、第三回。実はこれまで使っていたのは、com.sun.jnaパッケージだったのだが、maven centralで惹いてくると、jna-3.0.9しかなかったため、これを利用していた。しかし、ネットのドキュメントのバージョンは、3.2.7とか。実際は、https://github.com/twall/jna ここで開発されているのがjna-4.0.0なのだが、これはmavenでサポートされていない個別コンパイルのものだと思ってた。しかし、違った。net.dev.java.jnaと指定すれば、とってこれた。

jnaのドキュメントをみてると、実はライブラリのバインドの方法は2つあるようだ。

public class HelloWorld {

    // This is the standard, stable way of mapping, which supports extensive
    // customization and mapping of Java to native types.

    public interface CLibrary extends Library {
        CLibrary INSTANCE = (CLibrary)
            Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),
                               CLibrary.class);

        void printf(String format, Object... args);
    }
}

こちらはinner classで読み込む方法。Clibrary.INSTANCE...といちいち書かなければいけないのがおっくうだった。

public class HelloWorld {

    public static native double cos(double x);
    public static native double sin(double x);

    static {
        Native.register(Platform.C_LIBRARY_NAME);
    }

    public static void main(String[] args) {
        System.out.println("cos(0)=" + cos(0));
        System.out.println("sin(0)=" + sin(0));
    }
}

そしてこちらがDirect mappingという方法。extra performanceが必要な場合は、と書いてあるので、こちらのほうがよさそうだ。というわけで、Direct mappingにバインドを移行する。関数がいままでpublic static だったのが、public static native になる。おそらく、Java側のJNIアクセスにあうようなバイナリをメモリに生成するのだろう。jna3での、一つ一つの関数ラッパをメモリ上に生成する方法に比べて早い気がする。

しかし、そこで問題発生。Libraryの初期化で失敗してしまう。
問題になっていたのは、以下の関数。

public static native int epoll_wait (int epfd, EpollEvent[] ev, int maxEvents, int timeout);

どうやら、Structureは使えないようだ。StackOverflowに聞いて、解決。Structureの場合は、Structure[0].getPointer()を渡すようにしろ、とのこと。なるほど。しかし型チェックははずされるので、publicにはしないほうが良いだろう。

というわけで、無事epollのバインドは終了。微妙にsetAlignTypeも変更する必要があった。

    // from sys/epoll.h
    public static class EpollData extends Union {
        public int fd;
        public long u64; // we don't need, but make size 8.
        public EpollData() {
            super();
        }
        public EpollData(int fd_or_u32) {
            super();
            this.fd = fd_or_u32;
            setType(Integer.TYPE);
        }
        public EpollData(long u64) {
            super();
            this.u64 = u64;
            setType(Long.TYPE);
        }
        public static class ByReference extends EpollData implements Structure.ByReference {}
        public static class ByValue extends EpollData implements Structure.ByValue {}
    }

    public static class EpollEvent extends Structure {
        public int events;
        public EpollData data;

        public EpollEvent() {
            super(Structure.ALIGN_NONE);
        }

        protected List getFieldOrder() {
            return Arrays.asList("events", "data");
        }

        public static class ByReference extends EpollEvent implements  Structure.ByReference { }
        public static class ByValue extends EpollEvent implements Structure.ByValue { }
    }

    private static native int epoll_create(int size);
    private static native int epoll_create1(int flags);
    private static native int epoll_ctl(int epfd, int op, int fd, EpollEvent.ByReference ev);
    private static native int epoll_wait (int epfd, Pointer /*EpollEvent[] */ ev, int maxEvents, int timeout);