JNI是否保留errno?

问题描述 投票:1回答:1

我正在编写一些JNI代码来包装一些C函数。其中某些C函数集errno是错误的情况。如果我可以将异常处理从JNI代码转移到Java代码,则我的代码会更简单。我的计划是在发生错误的情况下必须让JNI函数返回null,然后在Java代码查询errno中构造并抛出异常。为此,JNI必须保持errno不变。

java java-native-interface
1个回答
3
投票

如果我是你,我会尽快例外处理

#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内,您可以轻松访问errnomessage


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());
© www.soinside.com 2019 - 2024. All rights reserved.