Skip to content

Commit

Permalink
feat(core) virtual errno/GetLastError() parameters
Browse files Browse the repository at this point in the history
This change replaces the thread-local storage of errno & GetLastError()
in JNIEnv->reserved2 with virtual output parameters passed explicitly by
the caller.
  • Loading branch information
Spasi committed Oct 4, 2024
1 parent 63c08d5 commit 2b12f5e
Show file tree
Hide file tree
Showing 60 changed files with 1,704 additions and 1,098 deletions.
2 changes: 1 addition & 1 deletion build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -854,7 +854,7 @@
<include name="org/lwjgl/demo/stb/**" if:set="test.stb"/>

<include name="org/lwjgl/demo/system/jawt/**" if:set="test.jawt"/>
<include name="org/lwjgl/demo/system/linux/liburing/**" if:set="platform.linux"/>
<include name="org/lwjgl/demo/system/linux/liburing/**"/>

<include name="org/lwjgl/demo/util/*.java"/>
<include name="org/lwjgl/demo/util/freetype/**" if:true="${binding.freetype}"/>
Expand Down
4 changes: 4 additions & 0 deletions config/cli/classpath.args
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ bin/classes/test:\
bin/classes/samples:\
modules/samples/src/test/resources:\
bin/libs/java/testng.jar:\
bin/libs/java/jcommander.jar:\
bin/libs/java/jquery.jar:\
bin/libs/java/slf4j-api.jar:\
bin/libs/java/slf4j-jdk14.jar:\
bin/libs/java/joml.jar:\
bin/libs/java/jmh-core.jar:\
bin/libs/java/commons-math3.jar:\
Expand Down
4 changes: 4 additions & 0 deletions config/cli/classpath.win.args
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ bin/classes/test;\
bin/classes/samples;\
modules/samples/src/test/resources;\
bin/libs/java/testng.jar;\
bin/libs/java/jcommander.jar;\
bin/libs/java/jquery.jar;\
bin/libs/java/slf4j-api.jar;\
bin/libs/java/slf4j-jdk14.jar;\
bin/libs/java/joml.jar;\
bin/libs/java/jmh-core.jar;\
bin/libs/java/commons-math3.jar;\
Expand Down
4 changes: 0 additions & 4 deletions config/native-image/META-INF/native-image/jni-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,5 @@
{
"name":"org.lwjgl.system.CallbackI",
"methods":[{"name":"callback","parameterTypes":["long","long"] }]
},
{
"name":"org.lwjgl.system.ThreadLocalUtil",
"methods":[{"name":"setupEnvData","parameterTypes":[] }]
}
]
5 changes: 5 additions & 0 deletions doc/notes/3.3.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@ This build includes the following changes:
- Core: Fixed support for `va_list` parameters.

#### Breaking Changes

- Core: Replaced thread-local storage of `errno/GetLastError()` with virtual output parameters. (#1003)
* The `LibCErrno.getErrno()` and `WinBase.getLastError()` methods have been removed.
* System calls in `org.lwjgl.system.linux.*`, `org.lwjgl.system.windows.*` and `org.lwjgl.opengl.WGL` now take an optional output parameter for the error code.
* This approach is similar to `Linker.Option.CaptureCallState` in Project Panama's FFM API.
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ class Func(
private fun getNativeParams(
withExplicitFunctionAddress: Boolean = true,
withJNIEnv: Boolean = false,
withAutoSizeResultParams: Boolean = true
withAutoSizeResultParams: Boolean = true,
withCaptureCallState: Boolean = true
) = parameters.asSequence()
.let { p -> if (withExplicitFunctionAddress) p else p.filter { it !== EXPLICIT_FUNCTION_ADDRESS } }
.let { p -> if (withJNIEnv) p else p.filter { it !== JNI_ENV } }
Expand All @@ -90,6 +91,7 @@ class Func(
else
p.filter { !((it.has<Virtual>() && !it.has<AutoSizeResultParam>()) || (it.isAutoSizeResultOut && hideAutoSizeResultParam)) }
}
.let { p -> if (withCaptureCallState) p else p.filter { !(it === parameters[0] && CaptureCallState.matches(it)) } }

/** Returns a parameter that has the specified ReferenceModifier with the specified reference. Returns null if no such parameter exists. */
internal inline fun <reified T> getReferenceParam(reference: String)
Expand Down Expand Up @@ -176,7 +178,7 @@ class Func(
internal val hasArrayOverloads
get() = !has<OffHeapOnly>() && this.parameters
.count { it.isAutoSizeResultOut }
.let { autoSizeResultOutParams -> this.parameters.asSequence().any { it.has<MultiType>() || it.isArrayParameter(autoSizeResultOutParams) } }
.let { autoSizeResultOutParams -> this.parameters.asSequence().any { (it.has<MultiType>() || it.isArrayParameter(autoSizeResultOutParams)) && !(it === this.parameters[0] && CaptureCallState.matches(it)) } }

private val ReturnValue.javaMethodType
get() = this.nativeType.let {
Expand Down Expand Up @@ -1874,7 +1876,7 @@ class Func(
if (nativeClass.callingConvention !== CallingConvention.DEFAULT)
print("APIENTRY ")
print("*${nativeName}PROC) (")
val nativeParams = getNativeParams(withExplicitFunctionAddress = false, withJNIEnv = true)
val nativeParams = getNativeParams(withExplicitFunctionAddress = false, withJNIEnv = true, withCaptureCallState = false)
if (nativeParams.any()) {
printList(nativeParams) {
it.toNativeType(nativeClass.binding)
Expand Down Expand Up @@ -1957,7 +1959,7 @@ class Func(
getNativeParams(withExplicitFunctionAddress = false)
.filter { it.nativeType.castAddressToPointer }
.forEach {
val variableType = it.toNativeType(nativeClass.binding, pointerMode = true)
val variableType = it.toNativeType(if (nativeClass.binding == null || (it === parameters[0] && CaptureCallState.matches(it))) null else nativeClass.binding, pointerMode = true)

print(t)
if (it.nativeType is FunctionType && variableType.contains("(*)")) {
Expand Down Expand Up @@ -2061,7 +2063,7 @@ class Func(
print("(*$JNIENV)->")
print(nativeName)
if (!has<Macro> { !function }) print('(')
printList(getNativeParams(withExplicitFunctionAddress = false, withJNIEnv = true)) { param ->
printList(getNativeParams(withExplicitFunctionAddress = false, withJNIEnv = true, withCaptureCallState = false)) { param ->
param.nativeType.let {
val name = param.name
if (it is StructType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,37 @@ class Code(
)
}

val SaveErrno = Code(nativeAfterCall = "${t}saveErrno();")
enum class CaptureCallState(val param: Parameter, val code: Code) {
@Suppress("EnumEntryName")
errno(
Check(1)..nullable..Parameter(int.p, "_errno", "optionally returns the {@code errno} value after this function is called"),
Code(nativeAfterCall = "${t}if (_errno != NULL) *_errno = errno;")
),
GetLastError(
Check(1)..nullable..Parameter(
IntegerType("DWORD", PrimitiveMapping.INT).p,
"_GetLastError",
"optionally returns the result of {@code GetLastError()} after this function is called"
),
Code(nativeAfterCall = "${t}if (_GetLastError != NULL) *_GetLastError = GetLastError();")
);

companion object {
internal fun apply(func: Func): Func {
if (func.parameters.isNotEmpty()) {
when (func.parameters[0]) {
errno.param -> errno.code..func
GetLastError.param -> GetLastError.code..func
}
}
return func
}

internal fun matches(param: Parameter) =
param === errno.param ||
param === GetLastError.param
}
}

fun statement(code: String, applyTo: ApplyTo = ApplyTo.BOTH): List<Code.Statement> = arrayListOf(Code.Statement(code, applyTo))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,8 @@ class NativeClass internal constructor(
require(_functions.put(name, func) == null) {
"The $name function is already defined in ${this@NativeClass.className}."
}
return func

return CaptureCallState.apply(func)
}

fun customMethod(method: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,55 +9,61 @@

EXTERN_C_ENTER

JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_FCNTL_nopen(JNIEnv *__env, jclass clazz, jlong pathnameAddress, jint flags, jint mode) {
JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_FCNTL_nopen(JNIEnv *__env, jclass clazz, jlong _errnoAddress, jlong pathnameAddress, jint flags, jint mode) {
int *_errno = (int *)(uintptr_t)_errnoAddress;
char const *pathname = (char const *)(uintptr_t)pathnameAddress;
jint __result;
UNUSED_PARAMS(__env, clazz)
__result = (jint)open(pathname, flags, (mode_t)mode);
saveErrno();
if (_errno != NULL) *_errno = errno;
return __result;
}

JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_FCNTL_nopenat(JNIEnv *__env, jclass clazz, jint dirfd, jlong pathnameAddress, jint flags, jint mode) {
JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_FCNTL_nopenat(JNIEnv *__env, jclass clazz, jlong _errnoAddress, jint dirfd, jlong pathnameAddress, jint flags, jint mode) {
int *_errno = (int *)(uintptr_t)_errnoAddress;
char const *pathname = (char const *)(uintptr_t)pathnameAddress;
jint __result;
UNUSED_PARAMS(__env, clazz)
__result = (jint)openat(dirfd, pathname, flags, (mode_t)mode);
saveErrno();
if (_errno != NULL) *_errno = errno;
return __result;
}

JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_FCNTL_ncreat(JNIEnv *__env, jclass clazz, jlong pathnameAddress, jint mode) {
JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_FCNTL_ncreat(JNIEnv *__env, jclass clazz, jlong _errnoAddress, jlong pathnameAddress, jint mode) {
int *_errno = (int *)(uintptr_t)_errnoAddress;
char const *pathname = (char const *)(uintptr_t)pathnameAddress;
jint __result;
UNUSED_PARAMS(__env, clazz)
__result = (jint)creat(pathname, (mode_t)mode);
saveErrno();
if (_errno != NULL) *_errno = errno;
return __result;
}

JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_FCNTL_fcntl(JNIEnv *__env, jclass clazz, jint fd, jint cmd) {
JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_FCNTL_nfcntl(JNIEnv *__env, jclass clazz, jlong _errnoAddress, jint fd, jint cmd) {
int *_errno = (int *)(uintptr_t)_errnoAddress;
jint __result;
UNUSED_PARAMS(__env, clazz)
__result = (jint)fcntl(fd, cmd);
saveErrno();
if (_errno != NULL) *_errno = errno;
return __result;
}

JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_FCNTL_nfcntli(JNIEnv *__env, jclass clazz, jint fd, jint cmd, jint arg) {
JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_FCNTL_nfcntli(JNIEnv *__env, jclass clazz, jlong _errnoAddress, jint fd, jint cmd, jint arg) {
int *_errno = (int *)(uintptr_t)_errnoAddress;
jint __result;
UNUSED_PARAMS(__env, clazz)
__result = (jint)fcntl(fd, cmd, arg);
saveErrno();
if (_errno != NULL) *_errno = errno;
return __result;
}

JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_FCNTL_nfcntlp(JNIEnv *__env, jclass clazz, jint fd, jint cmd, jlong argAddress) {
JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_FCNTL_nfcntlp(JNIEnv *__env, jclass clazz, jlong _errnoAddress, jint fd, jint cmd, jlong argAddress) {
int *_errno = (int *)(uintptr_t)_errnoAddress;
void *arg = (void *)(uintptr_t)argAddress;
jint __result;
UNUSED_PARAMS(__env, clazz)
__result = (jint)fcntl(fd, cmd, arg);
saveErrno();
if (_errno != NULL) *_errno = errno;
return __result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,23 @@

EXTERN_C_ENTER

JNIEXPORT jlong JNICALL Java_org_lwjgl_system_linux_MMAN_mmap(JNIEnv *__env, jclass clazz, jlong addrAddress, jlong length, jint prot, jint flags, jint fd, jlong offset) {
JNIEXPORT jlong JNICALL Java_org_lwjgl_system_linux_MMAN_nmmap(JNIEnv *__env, jclass clazz, jlong _errnoAddress, jlong addrAddress, jlong length, jint prot, jint flags, jint fd, jlong offset) {
int *_errno = (int *)(uintptr_t)_errnoAddress;
void *addr = (void *)(uintptr_t)addrAddress;
jlong __result;
UNUSED_PARAMS(__env, clazz)
__result = (jlong)(uintptr_t)mmap(addr, (size_t)length, prot, flags, fd, (off_t)offset);
saveErrno();
if (_errno != NULL) *_errno = errno;
return __result;
}

JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_MMAN_nmunmap(JNIEnv *__env, jclass clazz, jlong addrAddress, jlong length) {
JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_MMAN_nmunmap(JNIEnv *__env, jclass clazz, jlong _errnoAddress, jlong addrAddress, jlong length) {
int *_errno = (int *)(uintptr_t)_errnoAddress;
void *addr = (void *)(uintptr_t)addrAddress;
jint __result;
UNUSED_PARAMS(__env, clazz)
__result = (jint)munmap(addr, (size_t)length);
saveErrno();
if (_errno != NULL) *_errno = errno;
return __result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@

EXTERN_C_ENTER

JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_Socket_socket(JNIEnv *__env, jclass clazz, jint __domain, jint __type, jint __protocol) {
JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_Socket_nsocket(JNIEnv *__env, jclass clazz, jlong _errnoAddress, jint __domain, jint __type, jint __protocol) {
int *_errno = (int *)(uintptr_t)_errnoAddress;
jint __result;
UNUSED_PARAMS(__env, clazz)
__result = (jint)socket(__domain, __type, __protocol);
saveErrno();
if (_errno != NULL) *_errno = errno;
return __result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,24 @@

EXTERN_C_ENTER

JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_Stat_nstat(JNIEnv *__env, jclass clazz, jlong __fileAddress, jlong __bufAddress) {
JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_Stat_nstat(JNIEnv *__env, jclass clazz, jlong _errnoAddress, jlong __fileAddress, jlong __bufAddress) {
int *_errno = (int *)(uintptr_t)_errnoAddress;
char const *__file = (char const *)(uintptr_t)__fileAddress;
struct stat *__buf = (struct stat *)(uintptr_t)__bufAddress;
jint __result;
UNUSED_PARAMS(__env, clazz)
__result = (jint)stat(__file, __buf);
saveErrno();
if (_errno != NULL) *_errno = errno;
return __result;
}

JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_Stat_nfstat(JNIEnv *__env, jclass clazz, jint __fd, jlong __bufAddress) {
JNIEXPORT jint JNICALL Java_org_lwjgl_system_linux_Stat_nfstat(JNIEnv *__env, jclass clazz, jlong _errnoAddress, jint __fd, jlong __bufAddress) {
int *_errno = (int *)(uintptr_t)_errnoAddress;
struct stat *__buf = (struct stat *)(uintptr_t)__bufAddress;
jint __result;
UNUSED_PARAMS(__env, clazz)
__result = (jint)fstat(__fd, __buf);
saveErrno();
if (_errno != NULL) *_errno = errno;
return __result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,59 +9,65 @@

EXTERN_C_ENTER

JNIEXPORT jlong JNICALL Java_org_lwjgl_system_linux_UIO_nreadv(JNIEnv *__env, jclass clazz, jint __fd, jlong __iovecAddress, jint __count) {
JNIEXPORT jlong JNICALL Java_org_lwjgl_system_linux_UIO_nreadv(JNIEnv *__env, jclass clazz, jlong _errnoAddress, jint __fd, jlong __iovecAddress, jint __count) {
int *_errno = (int *)(uintptr_t)_errnoAddress;
struct iovec const *__iovec = (struct iovec const *)(uintptr_t)__iovecAddress;
jlong __result;
UNUSED_PARAMS(__env, clazz)
__result = (jlong)readv(__fd, __iovec, __count);
saveErrno();
if (_errno != NULL) *_errno = errno;
return __result;
}

JNIEXPORT jlong JNICALL Java_org_lwjgl_system_linux_UIO_nwritev(JNIEnv *__env, jclass clazz, jint __fd, jlong __iovecAddress, jint __count) {
JNIEXPORT jlong JNICALL Java_org_lwjgl_system_linux_UIO_nwritev(JNIEnv *__env, jclass clazz, jlong _errnoAddress, jint __fd, jlong __iovecAddress, jint __count) {
int *_errno = (int *)(uintptr_t)_errnoAddress;
struct iovec const *__iovec = (struct iovec const *)(uintptr_t)__iovecAddress;
jlong __result;
UNUSED_PARAMS(__env, clazz)
__result = (jlong)writev(__fd, __iovec, __count);
saveErrno();
if (_errno != NULL) *_errno = errno;
return __result;
}

JNIEXPORT jlong JNICALL Java_org_lwjgl_system_linux_UIO_npreadv(JNIEnv *__env, jclass clazz, jint __fd, jlong __iovecAddress, jint __count, jlong __offset) {
JNIEXPORT jlong JNICALL Java_org_lwjgl_system_linux_UIO_npreadv(JNIEnv *__env, jclass clazz, jlong _errnoAddress, jint __fd, jlong __iovecAddress, jint __count, jlong __offset) {
int *_errno = (int *)(uintptr_t)_errnoAddress;
struct iovec const *__iovec = (struct iovec const *)(uintptr_t)__iovecAddress;
jlong __result;
UNUSED_PARAMS(__env, clazz)
__result = (jlong)preadv(__fd, __iovec, __count, (off_t)__offset);
saveErrno();
if (_errno != NULL) *_errno = errno;
return __result;
}

JNIEXPORT jlong JNICALL Java_org_lwjgl_system_linux_UIO_npwritev(JNIEnv *__env, jclass clazz, jint __fd, jlong __iovecAddress, jint __count, jlong __offset) {
JNIEXPORT jlong JNICALL Java_org_lwjgl_system_linux_UIO_npwritev(JNIEnv *__env, jclass clazz, jlong _errnoAddress, jint __fd, jlong __iovecAddress, jint __count, jlong __offset) {
int *_errno = (int *)(uintptr_t)_errnoAddress;
struct iovec const *__iovec = (struct iovec const *)(uintptr_t)__iovecAddress;
jlong __result;
UNUSED_PARAMS(__env, clazz)
__result = (jlong)pwritev(__fd, __iovec, __count, (off_t)__offset);
saveErrno();
if (_errno != NULL) *_errno = errno;
return __result;
}

JNIEXPORT jlong JNICALL Java_org_lwjgl_system_linux_UIO_nprocess_1vm_1readv(JNIEnv *__env, jclass clazz, jint __pid, jlong __lvecAddress, jlong __liovcnt, jlong __rvecAddress, jlong __riovcnt, jlong __flags) {
JNIEXPORT jlong JNICALL Java_org_lwjgl_system_linux_UIO_nprocess_1vm_1readv(JNIEnv *__env, jclass clazz, jlong _errnoAddress, jint __pid, jlong __lvecAddress, jlong __liovcnt, jlong __rvecAddress, jlong __riovcnt, jlong __flags) {
int *_errno = (int *)(uintptr_t)_errnoAddress;
struct iovec const *__lvec = (struct iovec const *)(uintptr_t)__lvecAddress;
struct iovec const *__rvec = (struct iovec const *)(uintptr_t)__rvecAddress;
jlong __result;
UNUSED_PARAMS(__env, clazz)
__result = (jlong)process_vm_readv((pid_t)__pid, __lvec, (unsigned long int)__liovcnt, __rvec, (unsigned long int)__riovcnt, (unsigned long int)__flags);
saveErrno();
if (_errno != NULL) *_errno = errno;
return __result;
}

JNIEXPORT jlong JNICALL Java_org_lwjgl_system_linux_UIO_nprocess_1vm_1writev(JNIEnv *__env, jclass clazz, jint __pid, jlong __lvecAddress, jlong __liovcnt, jlong __rvecAddress, jlong __riovcnt, jlong __flags) {
JNIEXPORT jlong JNICALL Java_org_lwjgl_system_linux_UIO_nprocess_1vm_1writev(JNIEnv *__env, jclass clazz, jlong _errnoAddress, jint __pid, jlong __lvecAddress, jlong __liovcnt, jlong __rvecAddress, jlong __riovcnt, jlong __flags) {
int *_errno = (int *)(uintptr_t)_errnoAddress;
struct iovec const *__lvec = (struct iovec const *)(uintptr_t)__lvecAddress;
struct iovec const *__rvec = (struct iovec const *)(uintptr_t)__rvecAddress;
jlong __result;
UNUSED_PARAMS(__env, clazz)
__result = (jlong)process_vm_writev((pid_t)__pid, __lvec, (unsigned long int)__liovcnt, __rvec, (unsigned long int)__riovcnt, (unsigned long int)__flags);
saveErrno();
if (_errno != NULL) *_errno = errno;
return __result;
}

Expand Down
Loading

0 comments on commit 2b12f5e

Please sign in to comment.