Hi all,

This change enhances the Java foreign functions and memory API to allow users 
to inject thread-locals before a downcall. 

The lvalue `errno` is used for error handling in C. The C11 (draft) standard 
gives the following use-case example:
> Thus, a program that uses errnofor error checking should set it to zero 
> before a library function call,
then inspect it before a subsequent library function call. Of course, a library 
function can save the
value of errno on entry and then set it to zero, as long as the original value 
is restored if errno’s
value is still zero just before the return.

In the present day, it is possible to retrieve `errno` by using the API 
provided by `Linker.Option captureCallState`. This provides the Java-user a 
memory segment for thread-local data, that is populated by the JVM. The memory 
segment can be read using conventional FFM means, such as with a `VarHandle`. 

However, the contents of this segment is not used to populate the thread local 
data _before_ the downcall. As an example, in Java using the FFM API, an end 
user calling `strtol` and checking for `ERANGE` would do the following (in-line 
with the C standard footnote): set the captured call state buffer's `errno` to 
zero, perform a downcall, and then read the captured call state again to check 
if `errno` is still zero. While the memory segment sees `errno=0`, this is not 
actually written to the thread before execution. Thus, it is possible to 
observe stale or irrelevant error numbers. In this example, one could observe 
`ENOENT` after the `strtol` call, which is incorrect behaviour.

This PR flushes the captured call state to the thread local variables before 
the downcall, ensuring that procedures in accordance to the C standard are 
possible. Since this was somewhat invasive, I ported it to non-Oracle platforms 
as well. 

One thing worth noting is that the setting and retrieving of thread local data 
is now coupled. Meaning, if a user wants to retrieve e.g. `errno` after a 
downcall, it is their responsibility to ensure that `errno` is appropriately 
set beforehand in order to make a meaningful comparison with predetermined 
error ranges.

Testing: tiers 1-4 on Linux (x64, AArch64), macOS (x64, AArch64) and Windows 
(x64). I have built the JDK and run a [minimal but 
representative](https://gist.github.com/Arraying/41db1b093dfa5cc4bc49f1213584d520)
 test case on Oracle Linux 10 (x64) with Zero (native), s390x, powerpc64le and 
riscv64 (all QEMU). I've smoke tested these platforms in good faith, but it 
would be good if porters with access to actual hardware could ensure that this 
change is sound. I would recommend running `:jdk_foreign` or `tier1`, at least.

I will work on the CSR once the code changes and new specification have 
received sufficient review/feedback.

-------------

Commit messages:
 - Copyright.
 - Copyright.
 - Improve test coverage.
 - New JavaDoc.
 - Port to RISC-V.
 - Port to PowerPC.
 - Port to s390.
 - Port to Zero.
 - Port to x86_64.
 - Fix comment order.
 - ... and 3 more: https://git.openjdk.org/jdk/compare/56060367...9e48fa35

Changes: https://git.openjdk.org/jdk/pull/30059/files
  Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=30059&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8378559
  Stats: 319 lines in 11 files changed: 223 ins; 7 del; 89 mod
  Patch: https://git.openjdk.org/jdk/pull/30059.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/30059/head:pull/30059

PR: https://git.openjdk.org/jdk/pull/30059

Reply via email to