首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过JNI使用UNIX ucontext库的Java绿色线程。有可能吗?

通过JNI使用UNIX ucontext库的Java绿色线程。有可能吗?
EN

Stack Overflow用户
提问于 2012-07-30 16:33:47
回答 1查看 293关注 0票数 1

我正在开发一个简单的,教育的例子绿色(合作)量子线程使用ucontext。但我正面临着问题。下面提供的示例非常容易跟踪,我将感谢您为我提供的任何帮助:

TestApp.java

代码语言:javascript
复制
public class TestApp extends UThreadApp {
    public static void umain() {
        System.out.println("umain");
    }
}

UThreadApp.java

代码语言:javascript
复制
import java.io.*;

public class UThreadApp {
    public static void main(String[] args) {    
        long kernel = newContext();
        long umain = newUThread("TestApp", "umain");
        swap(kernel, umain);
        System.out.println("main");
    }

    native static long newContext();
    native static void swap(long oldc, long newc);
    native static long newUThread(String className, String method);

    static {
        System.loadLibrary("uthread");
    }
}

UThreadApp.c

代码语言:javascript
复制
#include <stdlib.h>
#include <ucontext.h>

#include "UThreadApp.h"

typedef struct {
    ucontext_t context;
    unsigned char stack[SIGSTKSZ];
} *Context;

ucontext_t *kernelContext;

/*
 * Class:     UThreadApp
 * Method:    newContext
 * Signature: ()J
 */
JNIEXPORT jlong JNICALL Java_UThreadApp_newContext
  (JNIEnv *env, jclass cls) {
    kernelContext = malloc(sizeof(ucontext_t));
    if (kernelContext == NULL)
        RTError("newContext: malloc: couldn't allocate memory for kernelContext");
    return (jlong) kernelContext;
}

/*
 * Class:     UThreadApp
 * Method:    swap
 * Signature: (JJ)V
 */
JNIEXPORT void JNICALL Java_UThreadApp_swap
  (JNIEnv *env, jclass cls, jlong oldc, jlong newc) {
    if (swapcontext((ucontext_t *)oldc, (ucontext_t *)newc) == -1)
        SysError("swap: swapcontext: couldn't switch context");
}

static JavaVM *jvm = NULL;

static void callback(jclass cls, jmethodID mid) {
    if (jvm == NULL)
        return;

    JNIEnv *env = NULL;
    jint res;
    res = (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
    if (res < 0)
        RTError("Attach VM Thread failed");

    /* JVM segfaults here */
    (*env)->CallStaticVoidMethod(env, cls, mid);
    //printf("umain\n");

    (*jvm)->DetachCurrentThread(jvm);
}

typedef void (*uthread_func)();

/*
 * Class:     UThreadApp
 * Method:    newUThread
 * Signature: (Ljava/lang/String;Ljava/lang/String;)J
 */
JNIEXPORT jlong JNICALL Java_UThreadApp_newUThread
  (JNIEnv *env, jclass cls, jstring className, jstring method) {

    /* find the current jvm */
    (*env)->GetJavaVM(env, &jvm);

    Context ctx = malloc(sizeof(*ctx));
    if (getcontext((ucontext_t *)ctx) == -1)
        RTError("newUThread: getcontext");
    sigdelset(&ctx->context.uc_sigmask, SIGALRM);
    ctx->context.uc_link = kernelContext;
    ctx->context.uc_stack.ss_sp = ctx->stack;
    ctx->context.uc_stack.ss_size = SIGSTKSZ;

    const char *str;
    str = (*env)->GetStringUTFChars(env, className, NULL);
    if (str == NULL)
        RTError("newUThread: className: GetStringUTFChars");
    jclass kls = (*env)->FindClass(env, str);
    if (kls == NULL)
        RTError("newUThread: FindClass: class not found");
    (*env)->ReleaseStringUTFChars(env, className, str);

    str = (*env)->GetStringUTFChars(env, method, NULL);
    if (str == NULL)
        RTError("newUThread: method: GetStringUTFChars");
    jmethodID mid = (*env)->GetStaticMethodID(env, kls, str, "()V");
    if (mid == NULL) {
        RTError("newUThread: GetStaticMethodID: method not found");
    }
    (*env)->ReleaseStringUTFChars(env, method, str);

    /* make global references */
    jclass gkls = (*env)->NewGlobalRef(env, kls);
    jmethodID gmid = (*env)->NewGlobalRef(env, mid);

    makecontext((ucontext_t *)ctx, (uthread_func)callback, 2, gkls, gmid);

    return (jlong) ctx;
}

代码创建kernelmain上下文,并将umain方法作为新的用户线程进行准备。swap切换上下文,保存内核并运行main。示例应打印:

umain

下一步

但是在(*env)->CallStaticVoidMethod(env, cls, mid)执行Java回调时出现了分段错误。这类代码很容易用C编写,但我在用Java开发它时遇到了一些微妙的问题。

Apache的javaflow不是一个选项,因为我发现开发一个时间量程的调度程序(使用SIGALRM)是非常困难的。

有什么想法吗?

EN

回答 1

Stack Overflow用户

发布于 2012-08-06 16:18:21

您不应该试图使一个jmethodID成为一个全局参考。它是一个方法ID,而不是一个引用。编译器应该抱怨这一点。尝试将该方法id全局保存在您的模块中。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11725706

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档