目次 | 前の項目 | 次の項目 Java Native Interface 仕様


5 - 呼び出し API


この呼び出し API により、ソフトウェアベンダーは Java VM を任意のネイティブアプリケーションにロードできるようになります。そのベンダーの提供する Java が実行可能なアプリケーションは、Java VM ソースコードにリンクする必要がありません。

この章では、呼び出し API の概要を述べ、そのあとですべての呼び出し API 関数を説明します。

Java VM の組み込み機能を向上させるため、JDK 1.1.2 の呼び出し API はいくつかの細かな点が拡張されています。


概要

次のコード例では、呼び出し API の関数の使用方法について説明します。この例では、C++ コードは Java VM を生成し、Main.test と呼ばれる static メソッドを起動します。明確にするために、エラーチェックを省略しました。

        #include <jni.h>       /* where everything is defined */
    
        ...
    
        JavaVM *jvm;       /* denotes a Java VM */
        JNIEnv *env;       /* pointer to native method interface */
    
        JDK1_1InitArgs vm_args; /* JDK 1.1 VM initialization arguments */
   
        vm_args.version = 0x00010001; /* New in 1.1.2: VM version */
        /* Get the default initialization arguments and set the class 
         * path */
        JNI_GetDefaultJavaVMInitArgs(&vm_args);
        vm_args.classpath = ...;
    
        /* load and initialize a Java VM, return a JNI interface 
         * pointer in env */
        JNI_CreateJavaVM(&jvm, &env, &vm_args);
    
        /* invoke the Main.test method using the JNI */
        jclass cls = env->FindClass("Main");
        jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V");
        env->CallStaticVoidMethod(cls, mid, 100);
    
        /* We are done. */
        jvm->DestroyJavaVM();
この例では、API の 3 つの関数を使用しています。呼び出し API はネイティブアプリケーションが JNI インタフェースポインタを使用して VM 機能にアクセスできるようにします。この設計は Netscape の JRI 埋め込みインタフェースと同様です。


VM の生成

JNI_CreateJavaVM() 関数は Java VM をロードして初期化し、JNI インタフェースポインタにポインタを返します。JNI_CreateJavaVM() を呼び出したスレッドは、「メインスレッド」とみなされます。


VM への接続

JNI インタフェースポインタ (JNIEnv) は、現在のスレッドでのみ有効です。別のスレッドが Java VM にアクセスする必要がある場合、これは最初に AttachCurrentThread() を呼び出し、それ自体を VM に接続し JNI インタフェースポインタを取得する必要があります。一度 VM に接続されると、ネイティブスレッドはネイティブメソッド内で実行中の普通の Java スレッドのように機能します。ネイティブスレッドは、それ自体を分離するために DetachCurrentThread() を呼び出すまで VM に接続されたままになります。


VM のアンロード

メインスレッドは、VM から分離できません。代わりに、VM 全体をアンロードするために DestroyJavaVM() を呼び出す必要があります。VM は、メインスレッドが唯一のユーザスレッドになるまで待機し、そのあとアンロードを実行します。ユーザスレッドには、Java スレッドおよび接続されたネイティブスレッドの両方があります。この制限は、Java スレッドまたは接続されたネイティブスレッドがロック、ウィンドウなどのシステムリソースを保持している可能性があるために存在します。VM は、自動的にこれらのリソースを開放することはできません。VM がアンロードされているときに、メインスレッドを唯一の実行中のスレッドであると制限することで、任意のスレッドが保持するシステムリソースを開放する負荷はプログラマに課せられます。


初期化構造体

Java VM によって異なる初期化引数が必要とされる可能性があります。現在および将来のすべての Java VM に対し、適切な、標準の初期化構造体を提供することは困難です。妥協策として、最初のフィールド (version) を初期化構造体の内容識別用に予約しておきます。JDK 1.1.2 を組み込んだネイティブアプリケーションは、このバージョンフィールドを 0x00010001 に設定する必要があります。実装によっては、JDK のサポートする初期化引数のいくつかを無視することを選択するかもしれませんが、VM 実装では、JDK と同じ初期化構造体を使うことをお勧めします。

バージョン番号 0x80000000 から 0xFFFFFFFF は予約されているので、VM 実装によって認識されません。

次のコードは、JDK 1.1.2 で Java VM の初期化に使われる構造体を示します。

    typedef struct JavaVMInitArgs {
       /* The first two fields were reserved in JDK 1.1, and
          formally introduced in JDK 1.1.2. */
       /* Java VM version */
        jint version;

       /* System properties. */
        char **properties;
    
       /* whether to check the Java source files are newer than 
        * compiled class files. */
        jint checkSource;
    
       /* maximum native stack size of Java-created threads. */
        jint nativeStackSize;
    
       /* maximum Java stack size. */
        jint javaStackSize;
    
       /* initial heap size. */
        jint minHeapSize;
    
       /* maximum heap size. */
        jint maxHeapSize;
    
       /* controls whether Java byte code should be verified:
        * 0 -- none, 1 -- remotely loaded code, 2 -- all code. */
        jint verifyMode;
    
       /* the local directory path for class loading. */
        const char *classpath;
    
       /* a hook for a function that redirects all VM messages. */
        jint (*vfprintf)(FILE *fp, const char *format, 
                         va_list args);
    
       /* a VM exit hook. */
        void (*exit)(jint code);
    
       /* a VM abort hook. */
        void (*abort)();
    
       /* whether to enable class GC. */
        jint enableClassGC;
    
       /* whether GC messages will appear. */
        jint enableVerboseGC;
    
       /* whether asynchronous GC is allowed. */
        jint disableAsyncGC;

       /* Three reserved fields. */ 
        jint reserved0;
        jint reserved1;
        jint reserved2;
    } JDK1_1InitArgs;
JDK 1.1.2 では、初期化構造体が提供するフックにより、ネイティブアプリケーションは VM メッセージをリダイレクトすることができ、VM の終了を制御することができるようになります。

次に示す構造体は、ネイティブスレッドが JDK 1.1.2 の Java VM に接続するとき、引数として渡されます。実際、JDK 1.1.2 へ接続するためにネイティブスレッドが要求する引数はありません。JDK1_1AttachArgs 構造体は、空の構造体を許さない C コンパイラ用の埋め込みスロットだけから成ります。

    typedef struct JDK1_1AttachArgs {
       /*
        * JDK 1.1 does not need any arguments to attach a
        * native thread. The padding is here to satisfy the C
        * compiler which does not permit empty structures.
        */
        void *__padding;
    } JDK1_1AttachArgs;

呼び出し API の関数

JavaVM 型は呼び出し API 関数テーブルのポインタです。次のコード例では、この関数テーブルを示します。

    typedef const struct JNIInvokeInterface *JavaVM;
    
    const struct JNIInvokeInterface ... = {
        NULL,
        NULL,
        NULL,
    
        DestroyJavaVM,
        AttachCurrentThread,
        DetachCurrentThread,
    };
次の 3 つの呼び出し API 関数に注意してください。JNI_GetDefaultJavaVMInitArgs()、JNI_GetCreatedJavaVMs()、および JNI_CreateJavaVM() は、Java VM 関数ではありません。これらの関数は既存の JavaVM 構造体がなくても使用することができます。


JNI_GetDefaultJavaVMInitArgs

jint JNI_GetDefaultJavaVMInitArgs(void *vm_args);

Java VM のデフォルト構成を返します。この関数を呼び出す前に、ネイティブコードは、vm_args->version フィールドを、VM にサポートさせたい JNI バージョンに設定しておかなければなりません。JDK 1.1.2 では、vm_args->version は、0x00010001 に設定する必要があります。 JDK 1.1 では、ネイティブコードでバージョンフィールドを設定する必要はありませんでした。下位互換のため、バージョンフィールドが設定されていない場合は、JDK 1.1.2 は、要求されたバージョンが 0x00010001 だと想定します。JDK の将来のバージョンでは、バージョンフィールドを適切な値に設定する必要があります。 この関数から復帰すると、vm_args->version は、VM がサポートする実際の JNI バージョンに設定されます。

パラメータ:

vm_args: デフォルト引数が入る VM 固有の初期化構造体へのポインタ

戻り値:

要求されたバージョンがサポートされている場合は 0、要求されたバージョンがサポートされていない場合は負の数を返します。


JNI_GetCreatedJavaVMs

jint JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen,
jsize *nVMs);

作成された Java VM をすべて返します。VM へのポインタは、作成された順にバッファ vmBuf に書き込まれます。しかし、エントリの bufLen 番号しか書き込みません。作成された VM の全体数は、*nVM で返します。

JDK 1.1 は 1 つのプロセスで、1 つの VM しかサポートしません。

パラメータ:

vmBuf: VM 構造体が配置されるバッファへのポインタ

bufLen: バッファの長さ

nVMs: 整数を参照するポインタ

戻り値:

成功した場合は 0、失敗した場合は負の数を返します。


JNI_CreateJavaVM

jint JNI_CreateJavaVM(JavaVM **p_vm, JNIEnv **p_env,
void *vm_args);

ロードして、Java VM を初期化します。現在のスレッドがメインスレッドになります。env 引数を、メインスレッドの JNI インタフェースポインタへ設定します。

JDK 1.1.2 は 1 つのプロセスで、1 つの VM しかサポートしません。vm_args のバージョンフィールドは、0x00010001 に設定する必要があります。

パラメータ:

p_vm: 結果の VM 構造体が配置される位置へのポインタ

p_env: メインスレッドの JNI インタフェースポインタが配置される位置へのポインタ

vm_args: Java VM 初期化引数

戻り値:

成功した場合は 0、失敗した場合は負の数を返します。


DestroyJavaVM

jint DestroyJavaVM(JavaVM *vm);

Java VM をアンロードし、そのリソースを回復します。メインスレッドだけが VM をアンロードできます。メインスレッドは、DestroyJavaVM() を呼び出すとき、唯一残ったユーザスレッドでなければなりません。

パラメータ:

vm: 破壊される Java VM

戻り値:

成功した場合は 0、失敗した場合は負の数を返します。

JDK 1.1.2 は VM のアンロードをサポートしません。


AttachCurrentThread

jint AttachCurrentThread(JavaVM *vm, JNIEnv **p_env,
void *thr_args);

現在のスレッドを Java VM へ接続します。JNIEnv 引数で JNI インタフェースポインタを返します。

すでに接続されているスレッドへの接続は、NO-OP です。

ネイティブスレッドを 2 つの Java VM へ同時に接続することはできません。

パラメータ:

vm: 現在のスレッドが接続される VM

p_env: 現在のスレッドの JNI インタフェースポインタが配置される位置へのポインタ

thr_args: VM 固有のスレッド接続引数

戻り値:

成功した場合は 0、失敗した場合は負の数を返します。


DetachCurrentThread

jint DetachCurrentThread(JavaVM *vm);

Java VM から現在のスレッドを分離します。このスレッドが保持する Java モニターはすべて解放されます。このスレッドが終了するのを待つ Java スレッドすべてに、通知が行われます。

Java VM を作成するスレッドであるメインスレッドを、VM から分離することができません。その代わり、VM 全体をアンロードするために、メインスレッドは JNI_DestroyJavaVM() を呼び出す必要があります。

パラメータ:

vm: 現在のスレッドが分離される VM

戻り値:

成功した場合は 0、失敗した場合は負の数を返します。


目次 | 前の項目 | 次の項目

Java Native Interface 仕様 (1997 年 3 月 15 日に dkramer によって生成された HTML)
Copyright © 1996, 1997 Sun Microsystems, Inc. All rights reserved
コメントの送付先: jni@java.sun.com