aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2023-03-07 01:02:19 +0100
committerSven Gothel <[email protected]>2023-03-07 01:02:19 +0100
commit1842451b0e49ac1899ed3ab3515021a6077aff92 (patch)
treeccbd7423b0127c89b687a4fd251e461bb5841a5a
parentb773048aee7ebfb00b7ae7b45ef9f49e88ebc5a4 (diff)
Clock: Consider return code on failed native clock_gettime(..) call; Add Win32 clock_gettime() implementation.
Consider return code on failed native clock_gettime(..) call - Return Instant.EPOCH for all Instant variations (essentially 0) - Return 0 for all 'long' variations (ms, ns) Add Win32 clock_gettime() implementation. - Source: https://github.com/Alexpux/mingw-w64/blob/master/mingw-w64-libraries/winpthreads/src/clock.c - Public Domain within mingw-w64, included here to simplify linkage. - Tested on Win10 64bit w/ TestTextRendererNEWT00, all values are OK
-rw-r--r--src/java/com/jogamp/common/os/Clock.java27
-rw-r--r--src/native/common/jau_sys_Clock.c174
2 files changed, 171 insertions, 30 deletions
diff --git a/src/java/com/jogamp/common/os/Clock.java b/src/java/com/jogamp/common/os/Clock.java
index 03a0040..9380442 100644
--- a/src/java/com/jogamp/common/os/Clock.java
+++ b/src/java/com/jogamp/common/os/Clock.java
@@ -32,8 +32,11 @@ public class Clock {
Platform.initSingleton(); // loads native gluegen_rt library
{
final long[/*2*/] val = { 0, 0 };
- getMonotonicStartupTimeImpl(val);
- t0 = Instant.ofEpochSecond(val[0], val[1]);
+ if( getMonotonicStartupTimeImpl(val) ) {
+ t0 = Instant.ofEpochSecond(val[0], val[1]);
+ } else {
+ t0 = Instant.EPOCH;
+ }
}
}
@@ -59,10 +62,13 @@ public class Clock {
*/
public static Instant getMonotonicTime() {
final long[/*2*/] val = { 0, 0 };
- getMonotonicTimeImpl(val);
- return Instant.ofEpochSecond(val[0], val[1]);
+ if( getMonotonicTimeImpl(val) ) {
+ return Instant.ofEpochSecond(val[0], val[1]);
+ } else {
+ return Instant.EPOCH;
+ }
}
- private static native void getMonotonicTimeImpl(final long[/*2*/] val);
+ private static native boolean getMonotonicTimeImpl(final long[/*2*/] val);
/**
* Returns current wall-clock real-time since Unix Epoch `00:00:00 UTC on 1970-01-01`.
@@ -80,10 +86,13 @@ public class Clock {
*/
public static Instant getWallClockTime() {
final long[/*2*/] val = { 0, 0 };
- getWallClockTimeImpl(val);
- return Instant.ofEpochSecond(val[0], val[1]);
+ if( getWallClockTimeImpl(val) ) {
+ return Instant.ofEpochSecond(val[0], val[1]);
+ } else {
+ return Instant.EPOCH;
+ }
}
- private static native void getWallClockTimeImpl(final long[/*2*/] val);
+ private static native boolean getWallClockTimeImpl(final long[/*2*/] val);
/**
* Returns the monotonic startup time since module startup as used in {@link #currentNanos()} and {@link #getMonotonicNanos()}.
@@ -91,7 +100,7 @@ public class Clock {
* @see #getMonotonicNanos()
*/
public static Instant getMonotonicStartupTime() { return t0; }
- private static native void getMonotonicStartupTimeImpl(final long[/*2*/] val);
+ private static native boolean getMonotonicStartupTimeImpl(final long[/*2*/] val);
/**
* Returns current monotonic nanoseconds since start of this application.
diff --git a/src/native/common/jau_sys_Clock.c b/src/native/common/jau_sys_Clock.c
index 4af3b85..e8a7210 100644
--- a/src/native/common/jau_sys_Clock.c
+++ b/src/native/common/jau_sys_Clock.c
@@ -27,6 +27,7 @@
#include <jni.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
#include <assert.h>
@@ -34,9 +35,17 @@
#include "com_jogamp_common_os_Clock.h"
-// #include <sys/time.h>
#include <time.h>
+#if defined(_WIN32)
+ #include <windows.h>
+ #ifndef IN_WINPTHREAD
+ #define IN_WINPTHREAD 1
+ #endif
+ #include "pthread.h"
+ #include "pthread_time.h"
+#endif
+
static const int64_t NanoPerMilli = 1000000L;
static const int64_t MilliPerOne = 1000L;
static const int64_t NanoPerSec = 1000000000L;
@@ -71,37 +80,42 @@ static jboolean throwNewRuntimeExceptionOnException(JNIEnv *env) {
}
-JNIEXPORT void JNICALL
+JNIEXPORT jboolean JNICALL
Java_com_jogamp_common_os_Clock_getMonotonicTimeImpl(JNIEnv *env, jclass clazz, jlongArray jval) {
(void)clazz;
// Avoid GetPrimitiveArrayCritical(), which occasionally hangs on system call ::clock_gettime()
struct timespec t = { .tv_sec = 0, .tv_nsec = 0 };
- clock_gettime(CLOCK_MONOTONIC, &t);
+ int res = clock_gettime(CLOCK_MONOTONIC, &t);
const jlong val[] = { (jlong)t.tv_sec, (jlong)t.tv_nsec };
(*env)->SetLongArrayRegion(env, jval, 0, 2, val);
+ return 0 == res ? JNI_TRUE : JNI_FALSE;
}
-JNIEXPORT void JNICALL
+JNIEXPORT jboolean JNICALL
Java_com_jogamp_common_os_Clock_getWallClockTimeImpl(JNIEnv *env, jclass clazz, jlongArray jval) {
(void)clazz;
// Avoid GetPrimitiveArrayCritical(), which occasionally hangs on system call ::clock_gettime()
struct timespec t = { .tv_sec = 0, .tv_nsec = 0 };
- clock_gettime(CLOCK_REALTIME, &t);
+ int res = clock_gettime(CLOCK_REALTIME, &t);
const jlong val[] = { (jlong)t.tv_sec, (jlong)t.tv_nsec };
(*env)->SetLongArrayRegion(env, jval, 0, 2, val);
+ return 0 == res ? JNI_TRUE : JNI_FALSE;
}
-JNIEXPORT void JNICALL
+JNIEXPORT jboolean JNICALL
Java_com_jogamp_common_os_Clock_getMonotonicStartupTimeImpl(JNIEnv *env, jclass clazz, jlongArray jval) {
(void)clazz;
// Avoid GetPrimitiveArrayCritical(), which occasionally hangs on system call ::clock_gettime()
- clock_gettime(CLOCK_MONOTONIC, &startup_t);
+ int res = clock_gettime(CLOCK_MONOTONIC, &startup_t);
const jlong val[] = { (jlong)startup_t.tv_sec, (jlong)startup_t.tv_nsec };
(*env)->SetLongArrayRegion(env, jval, 0, 2, val);
- throwNewRuntimeExceptionOnException(env);
+ if( throwNewRuntimeExceptionOnException(env) ) {
+ return JNI_FALSE;
+ }
+ return 0 == res ? JNI_TRUE : JNI_FALSE;
}
/**
@@ -118,14 +132,17 @@ Java_com_jogamp_common_os_Clock_currentNanos(JNIEnv *env, jclass clazz) {
(void)clazz;
struct timespec t = { .tv_sec = 0, .tv_nsec = 0 };
- clock_gettime(CLOCK_MONOTONIC, &t);
- struct timespec d = { .tv_sec = t.tv_sec - startup_t.tv_sec,
- .tv_nsec = t.tv_nsec - startup_t.tv_nsec };
- if ( 0 > d.tv_nsec ) {
- d.tv_nsec += NanoPerSec;
- d.tv_sec -= 1;
+ if( 0 == clock_gettime(CLOCK_MONOTONIC, &t) ) {
+ struct timespec d = { .tv_sec = t.tv_sec - startup_t.tv_sec,
+ .tv_nsec = t.tv_nsec - startup_t.tv_nsec };
+ if ( 0 > d.tv_nsec ) {
+ d.tv_nsec += NanoPerSec;
+ d.tv_sec -= 1;
+ }
+ return (jlong) ( (int64_t)d.tv_sec * NanoPerSec + (int64_t)d.tv_nsec );
+ } else {
+ return 0;
}
- return (jlong) ( (int64_t)d.tv_sec * NanoPerSec + (int64_t)d.tv_nsec );
}
/**
@@ -142,10 +159,13 @@ Java_com_jogamp_common_os_Clock_currentTimeMillis(JNIEnv *env, jclass clazz) {
(void)clazz;
struct timespec t = { .tv_sec = 0, .tv_nsec = 0 };
- clock_gettime(CLOCK_MONOTONIC, &t);
- int64_t res = (int64_t)t.tv_sec * MilliPerOne +
- (int64_t)t.tv_nsec / NanoPerMilli;
- return (jlong)res;
+ if( 0 == clock_gettime(CLOCK_MONOTONIC, &t) ) {
+ int64_t res = (int64_t)t.tv_sec * MilliPerOne +
+ (int64_t)t.tv_nsec / NanoPerMilli;
+ return (jlong)res;
+ } else {
+ return 0;
+ }
}
JNIEXPORT jlong JNICALL
@@ -154,7 +174,119 @@ Java_com_jogamp_common_os_Clock_wallClockSeconds(JNIEnv *env, jclass clazz) {
(void)clazz;
struct timespec t = { .tv_sec = 0, .tv_nsec = 0 };
- clock_gettime(CLOCK_REALTIME, &t);
- return (jlong)( (int64_t)( t.tv_sec ) );
+ if( 0 == clock_gettime(CLOCK_REALTIME, &t) ) {
+ return (jlong)( (int64_t)( t.tv_sec ) );
+ } else {
+ return 0;
+ }
+}
+
+#if defined(_WIN32)
+
+#define POW10_7 10000000
+#define POW10_9 1000000000
+
+/* Number of 100ns-seconds between the beginning of the Windows epoch
+ * (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970)
+ */
+#define DELTA_EPOCH_IN_100NS INT64_C(116444736000000000)
+
+static WINPTHREADS_INLINE int lc_set_errno(int result)
+{
+ if (result != 0) {
+ errno = result;
+ return -1;
+ }
+ return 0;
}
+/**
+ * Source: https://github.com/Alexpux/mingw-w64/blob/master/mingw-w64-libraries/winpthreads/src/clock.c
+ * Public Domain within mingw-w64, included here to simplify linkage.
+ *
+ * Get the time of the specified clock clock_id and stores it in the struct
+ * timespec pointed to by tp.
+ * @param clock_id The clock_id argument is the identifier of the particular
+ * clock on which to act. The following clocks are supported:
+ * <pre>
+ * CLOCK_REALTIME System-wide real-time clock. Setting this clock
+ * requires appropriate privileges.
+ * CLOCK_MONOTONIC Clock that cannot be set and represents monotonic
+ * time since some unspecified starting point.
+ * CLOCK_PROCESS_CPUTIME_ID High-resolution per-process timer from the CPU.
+ * CLOCK_THREAD_CPUTIME_ID Thread-specific CPU-time clock.
+ * </pre>
+ * @param tp The pointer to a timespec structure to receive the time.
+ * @return If the function succeeds, the return value is 0.
+ * If the function fails, the return value is -1,
+ * with errno set to indicate the error.
+ */
+int clock_gettime(clockid_t clock_id, struct timespec *tp)
+{
+ unsigned __int64 t;
+ LARGE_INTEGER pf, pc;
+ union {
+ unsigned __int64 u64;
+ FILETIME ft;
+ } ct, et, kt, ut;
+
+ switch(clock_id) {
+ case CLOCK_REALTIME:
+ {
+ GetSystemTimeAsFileTime(&ct.ft);
+ t = ct.u64 - DELTA_EPOCH_IN_100NS;
+ tp->tv_sec = t / POW10_7;
+ tp->tv_nsec = ((int) (t % POW10_7)) * 100;
+
+ return 0;
+ }
+
+ case CLOCK_MONOTONIC:
+ {
+ if (QueryPerformanceFrequency(&pf) == 0)
+ return lc_set_errno(EINVAL);
+
+ if (QueryPerformanceCounter(&pc) == 0)
+ return lc_set_errno(EINVAL);
+
+ tp->tv_sec = pc.QuadPart / pf.QuadPart;
+ tp->tv_nsec = (int) (((pc.QuadPart % pf.QuadPart) * POW10_9 + (pf.QuadPart >> 1)) / pf.QuadPart);
+ if (tp->tv_nsec >= POW10_9) {
+ tp->tv_sec ++;
+ tp->tv_nsec -= POW10_9;
+ }
+
+ return 0;
+ }
+
+ case CLOCK_PROCESS_CPUTIME_ID:
+ {
+ if(0 == GetProcessTimes(GetCurrentProcess(), &ct.ft, &et.ft, &kt.ft, &ut.ft))
+ return lc_set_errno(EINVAL);
+ t = kt.u64 + ut.u64;
+ tp->tv_sec = t / POW10_7;
+ tp->tv_nsec = ((int) (t % POW10_7)) * 100;
+
+ return 0;
+ }
+
+ case CLOCK_THREAD_CPUTIME_ID:
+ {
+ if(0 == GetThreadTimes(GetCurrentThread(), &ct.ft, &et.ft, &kt.ft, &ut.ft))
+ return lc_set_errno(EINVAL);
+ t = kt.u64 + ut.u64;
+ tp->tv_sec = t / POW10_7;
+ tp->tv_nsec = ((int) (t % POW10_7)) * 100;
+
+ return 0;
+ }
+
+ default:
+ break;
+ }
+
+ return lc_set_errno(EINVAL);
+}
+
+#endif
+