C共享全局变量在JNI中重置

时间:2016-10-25 10:38:40

标签: java c java-native-interface global-variables shared-libraries

目前在工作中我遇到了JNI下C共享库中的全局变量问题。目标是将数据库源代码编译到共享库中,以便在Java应用程序中本机使用它。

在编译共享库之前,我使用它的常规Makefile编译源代码(这个过程太详细了,不能在这里显示)。然后我按如下方式编译共享库:

gcc -shared -fPIC -DPIC -g -o ../java-lite/src/main/resources/libmonetdb5.so `find common gdk mal/mal mal/modules mal/optimizer sql embedded -name "*.o" | tr "\n" " "` -lpthread -lpcre -lz -lm -ldl

然后我做了Maven编译:

mvn clean install

在Java方面,我只是在应用程序的引导程序中加载共享库。

static {
    try {
        // Try load the library from java.library.path (it's working)
        System.loadLibrary("monetdb5");
    } catch (UnsatisfiedLinkError e) {
         //Load the library from the jar otherwise
        loadLibFromJar("monetdb5");
    }
}

问题出现在数据库加载上。这是JNI电话:

JNIEXPORT jobject JNICALL Java_nl_cwi_monetdb_embedded_MonetDBEmbeddedInstance_StartDatabase(JNIEnv *env, jclass class, jstring dbDirectory, jboolean silentFlag, jboolean sequentialFlag) {
    const char *dbdir_string_tmp = (*env)->GetStringUTFChars(env, dbDirectory, 0);
    char silent_char = 0, sequential_char = 0, *err = NULL, *databaseDirectory = strdup(dbdir_string_tmp);
    jclass resultClass;
    jmethodID resultConstructor;

    (void)class;
    if (silentFlag) {
        silent_char = 1;
    }
    if (sequentialFlag) {
        sequential_char = 1;
    }
    err = monetdb_startup(databaseDirectory, 1, 0);
    if (err != NULL) {
        (*env)->ReleaseStringUTFChars(env, dbDirectory, dbdir_string_tmp);
        resultClass = (*env)->FindClass(env, "java/io/IOException");
        (*env)->ThrowNew(env, resultClass, err);
        return NULL;
    }
    resultClass = (*env)->FindClass(env, "nl/cwi/monetdb/embedded/MonetDBEmbeddedInstance");
    resultConstructor = (*env)->GetMethodID(env, resultClass, "<init>", "(Ljava/lang/String;ZZZ)V");
    return (*env)->NewObject(env, resultClass, resultConstructor, dbDirectory, silentFlag, sequentialFlag, 1);
}

然后从数据库源代码中使用monetdb_startup函数:

static int monetdb_embedded_initialized = 0;

void* monetdb_connect(void) {
    Client conn = NULL;
    if (!monetdb_embedded_initialized) {
        return NULL;
    }
    conn = MCforkClient(&mal_clients[0]);
    if (!MCvalid((Client) conn)) {
        return NULL;
    }
    if (SQLinitClient(conn) != MAL_SUCCEED) {
        return NULL;
    }
    ((backend *) conn->sqlcontext)->mvc->session->auto_commit = 1;
    return conn;
}

char* monetdb_startup(char* dbdir, char silent, char sequential) {
    opt *set = NULL;
    volatile int setlen = 0;
    str retval = MAL_SUCCEED;
    char* sqres = NULL;
    void* res = NULL;
    void* c;

    if (setlocale(LC_CTYPE, "") == NULL) {
        retval = GDKstrdup("setlocale() failed");
        goto cleanup;
    }
    GDKfataljumpenable = 1;
    if(setjmp(GDKfataljump) != 0) {
        retval = GDKfatalmsg;
        // we will get here if GDKfatal was called.
        if (retval == NULL) {
            retval = GDKstrdup("GDKfatal() with unspecified error?");
        }
        goto cleanup;
    }

    if (monetdb_embedded_initialized) goto cleanup;

    if (!mal_init_inline) {
        mz_ulong decompress_len_mal = EMBEDDED_SCRIPT_SIZE_MAX;
        mz_ulong decompress_len_sql = EMBEDDED_SCRIPT_SIZE_MAX;
        mal_init_inline = GDKzalloc(decompress_len_mal);
        createdb_inline = GDKzalloc(decompress_len_sql);
        if (!mal_init_inline || !createdb_inline) {
            retval = GDKstrdup("Memory allocation failed");
            goto cleanup;
        }
        if (mz_uncompress(mal_init_inline, &decompress_len_mal, mal_init_inline_arr, sizeof(mal_init_inline_arr)) != 0 ||
            mz_uncompress(createdb_inline, &decompress_len_sql, createdb_inline_arr, sizeof(createdb_inline_arr)) != 0) {
            retval = GDKstrdup("Script decompression failed");
            goto cleanup;
        }
    }

    setlen = mo_builtin_settings(&set);
    setlen = mo_add_option(&set, setlen, opt_cmdline, "gdk_dbpath", dbdir);

    BBPaddfarm(dbdir, (1 << PERSISTENT) | (1 << TRANSIENT));
    if (GDKinit(set, setlen) == 0) {
        retval = GDKstrdup("GDKinit() failed");
        goto cleanup;
    }
    GDKsetenv("monet_mod_path", "");
    GDKsetenv("mapi_disable", "true");
    if (sequential) {
        GDKsetenv("sql_optimizer", "sequential_pipe");
    }

    if (silent) THRdata[0] = stream_blackhole_create();

    if (mal_init() != 0) { // mal_init() does not return meaningful codes on failure
        retval = GDKstrdup("mal_init() failed");
        goto cleanup;
    }

    if (silent) mal_clients[0].fdout = THRdata[0];

    monetdb_embedded_initialized = 1;
    c = monetdb_connect();
    if (c == NULL) {
        monetdb_embedded_initialized = 0;
        retval = GDKstrdup("Failed to initialize client");
        goto cleanup;
    }
    GDKfataljumpenable = 0;

    // we do not want to jump after this point, since we cannot do so between threads
    // sanity check, run a SQL query
    sqres = monetdb_query(c, "SELECT * FROM tables;", 1, &res);
    if (sqres != NULL) {
        monetdb_embedded_initialized = 0;
        retval = sqres;
        goto cleanup;
    }
    monetdb_cleanup_result(c, res);
    monetdb_disconnect(c);
cleanup:
    mo_free_options(set, setlen);
    return retval;

}

我们有一个全局变量&#34; monetdb_embedded_initialized&#34;表示数据库是否已初始化。在&#34; monetdb_startup&#34;函数,我们将变量设置为1然后我们在&#34; monetdb_connect&#34;上创建一个简短的连接。函数使用基本SQL查询进行小型功能测试。我们必须检查&#34; monetdb_embedded_initialized&#34;设置为1或不设置(对于后连接)。

问题是将monetdb_embedded_initialized设置为&#34; monetdb_startup&#34;,on&#34; monetdb_connect&#34;变量读为0,就像从未改变过一样。我测试了其他全局变量,实际上这种行为也会发生。

我在GDB上检查过只有一个线程调用这些函数,这个变量也只用在这些函数上。使用

在GDB上奇怪
p monetdb_embedded_initialized

在每次读取之前显示正确的值。我还用&#34; nm libmonetdb5.so&#34;检查了符号,所有这些都在那里。

我知道全局变量一般都存在问题,但我更愿意保留它们,因为数据库源代码有很多,删除它们会花费我们太长时间。

感谢您的关注

0 个答案:

没有答案