Java JNI是否保留errno?
我正在编写一些JNI代码来包装一些C函数。其中一些C函数setJava JNI是否保留errno?,java,java-native-interface,Java,Java Native Interface,我正在编写一些JNI代码来包装一些C函数。其中一些C函数seterrno出现错误。如果我能将异常处理从JNI代码移到Java代码,我的代码会更简单。我的计划是,在出现错误时,必须返回JNI函数null,然后在Java代码查询errno中构造并抛出异常。为了让这一切顺利进行,JNI必须让errno保持原样。如果我是你,我会尽快带着例外离开 #include <stdio.h> #include <stdlib.h> #include <string.h> #in
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);
}
}
更新 请注意,随着
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());
如果我是你,我会尽快带着例外离开
#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);
}
}
更新 请注意,随着
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());
我认为最好让JNI代码设置除
errno
之外的内容,并通过JNI公开的接口获取该错误值。errno
的问题在于它可以被许多操作所触及。最好是使用自己的错误值来指示错误,而不是依赖于errno
标准值。这样,您就可以报告errno
值范围内未涵盖的错误,并提供更好、更具信息性的诊断。请参阅中的讨论,可能无法保证errno
不会更改。所有代码所要做的就是调用一个函数,而C标准中的文档没有提到errno
:无论是否存在错误,只要在本国际标准的函数描述中未记录errno的使用,则可通过库函数调用将errno的值设置为非零我认为最好让JNI代码设置除errno
之外的内容,并通过JNI公开的接口获取该错误值。errno
的问题在于它可以被许多操作所触及。最好是使用自己的错误值来指示错误,而不是依赖于errno
标准值。这样,您就可以报告errno
值范围内未涵盖的错误,并提供更好、更具信息性的诊断。请参阅中的讨论,可能无法保证errno
不会更改。所有代码所要做的就是调用一个函数,而C标准中的文档没有提到errno
:“无论是否存在错误,只要在本国际标准的函数描述中未记录errno的使用,则可以通过库函数调用将errno的值设置为非零。”是的,这似乎是最好的做法。不幸的是,FindClass
和ThrowNew
也会失败。@PhilippeMarschall如果FindClass“java/lang/Exception”)
或ThrowNew
失败,除了调用中止()
,你就无能为力了。这可能是最好的方法,取决于你的需求。\n是的,这似乎是最好的办法。不幸的是FindClass
和ThrowNew
也可能失败。@PhilippeMarschall如果FindClass“java/lang/Exception”)
或ThrowNew
失败,那么除了调用中止()
,您就无能为力了。根据您的需求,这可能是最好的方法\