我正在编写一些JNI代码来包装一些C函数。其中某些C函数集errno
是错误的情况。如果我可以将异常处理从JNI代码转移到Java代码,则我的代码会更简单。我的计划是在发生错误的情况下必须让JNI函数返回null
,然后在Java代码查询errno
中构造并抛出异常。为此,JNI必须保持errno
不变。
如果我是你,我会尽快例外处理
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/errno.h>
#include "recipeNo019_ThrowException.h"
JNIEXPORT void JNICALL Java_recipeNo019_ThrowException_throwException
(JNIEnv * env, jobject obj) {
char exceptionBuffer[1024];
if(fopen("/this_will_fail", "r") == NULL) {
sprintf (exceptionBuffer, "%d:%s", errno, strerror(errno));
(*env)->ThrowNew (env,
(*env)->FindClass (env, "java/lang/Exception"),
exceptionBuffer);
}
}
然后,在Java
代码中,我将分解错误代码和错误消息。
然后,在Java
内,您可以轻松访问errno
和message
。
public static native void throwException();
...
...
try {
throwException();
} catch(Exception ex) {
ex.getMessage();
}
请注意,如果涉及到JNI
,事情可能会变得复杂(尤其是共享数据-errno
)。
您可以想象其中的一种情况-像这样:
public static class ErrnoGenerator implements Runnable {
boolean shouldIFail = false;
ThrowException exceptionGenerator = null;
public ErrnoGenerator(
ThrowException exceptionGenerator,
boolean shouldIFail) {
this.exceptionGenerator = exceptionGenerator;
this.shouldIFail = shouldIFail;
}
public void run() {
try {
if(shouldIFail) {
exceptionGenerator.throwException( shouldIFail );
Thread.sleep(1000);
System.out.println(
"true: expected == 2: "
+ exceptionGenerator.getErrno());
} else {
Thread.sleep(500);
exceptionGenerator.throwException( shouldIFail );
System.out.println(
"false: no expectations: "
+ exceptionGenerator.getErrno());
}
} catch (InterruptedException e) {
}
}
}
public static void main(String[] args) {
ThrowException thx = new ThrowException();
Thread t1 = new Thread(new ErrnoGenerator(thx, true));
Thread t2 = new Thread(new ErrnoGenerator(thx, false));
t1.start();
t2.start();
while(t1.isAlive() || t2.isAlive());
}
但是,即使没有基于Java
的线程调用JNI
,也可以输入竞争条件
// This will set errno to "2"
thx.throwException( true );
try {
Path file = Paths.get("/tmp/path-to-file");
byte[] buf = "hello".getBytes();
Files.write(file, buf);
} catch(Exception ex) {
}
// it's gone - errno contains something completely
// different to what you have expected to be found
System.out.println(
"true: expected == 2: "
+ thx.getErrno());