diff --git a/transport-native-kqueue/src/main/c/netty_kqueue_native.c b/transport-native-kqueue/src/main/c/netty_kqueue_native.c index a2a5a874a2..86f2d18586 100644 --- a/transport-native-kqueue/src/main/c/netty_kqueue_native.c +++ b/transport-native-kqueue/src/main/c/netty_kqueue_native.c @@ -139,15 +139,11 @@ static jint netty_kqueue_native_keventWait(JNIEnv* env, jclass clazz, jint kqueu } netty_unix_util_clock_gettime(waitClockId, &nowTs); - // beforeTs will store the time difference to check for overflow - beforeTs.tv_sec = nowTs.tv_sec - beforeTs.tv_sec; - beforeTs.tv_nsec = nowTs.tv_nsec - beforeTs.tv_nsec; - // Now subtract the time difference - timeoutTs.tv_sec -= beforeTs.tv_sec; - timeoutTs.tv_nsec -= beforeTs.tv_nsec; - if (beforeTs.tv_sec < 0 || beforeTs.tv_nsec < 0 || (timeoutTs.tv_sec <= 0 && timeoutTs.tv_nsec <= 0)) { + if (netty_unix_util_timespec_subtract_ns(&timeoutTs, + netty_unix_util_timespec_elapsed_ns(&beforeTs, &nowTs))) { return 0; } + beforeTs = nowTs; // https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2 // When kevent() call fails with EINTR error, all changes in the changelist have been applied. diff --git a/transport-native-unix-common/src/main/c/netty_unix_util.c b/transport-native-unix-common/src/main/c/netty_unix_util.c index f21d4c6809..7ff91c5a94 100644 --- a/transport-native-unix-common/src/main/c/netty_unix_util.c +++ b/transport-native-unix-common/src/main/c/netty_unix_util.c @@ -19,11 +19,12 @@ #include #include "netty_unix_util.h" +static const uint64_t NETTY_BILLION = 1000000000L; + #ifdef NETTY_USE_MACH_INSTEAD_OF_CLOCK #include #include -static const uint64_t NETTY_BILLION = 1000000000L; #endif /* NETTY_USE_MACH_INSTEAD_OF_CLOCK */ @@ -101,6 +102,25 @@ char* netty_unix_util_parse_package_prefix(const char* libraryPathName, const ch } // util methods +uint64_t netty_unix_util_timespec_elapsed_ns(const struct timespec* begin, const struct timespec* end) { + return NETTY_BILLION * (end->tv_sec - begin->tv_sec) + (end->tv_nsec - begin->tv_nsec); +} + +jboolean netty_unix_util_timespec_subtract_ns(struct timespec* ts, uint64_t nanos) { + const uint64_t seconds = nanos / NETTY_BILLION; + nanos -= seconds * NETTY_BILLION; + // If there are too many nanos we steal from seconds to avoid underflow on nanos. This way we + // only have to worry about underflow on tv_sec. + if (nanos > ts->tv_nsec) { + --(ts->tv_sec); + ts->tv_nsec += NETTY_BILLION; + } + const jboolean underflow = ts->tv_sec < seconds; + ts->tv_sec -= seconds; + ts->tv_nsec -= nanos; + return underflow; +} + int netty_unix_util_clock_gettime(clockid_t clockId, struct timespec* tp) { #ifdef NETTY_USE_MACH_INSTEAD_OF_CLOCK uint64_t timeNs; diff --git a/transport-native-unix-common/src/main/c/netty_unix_util.h b/transport-native-unix-common/src/main/c/netty_unix_util.h index 9f75e32005..aba672dc5f 100644 --- a/transport-native-unix-common/src/main/c/netty_unix_util.h +++ b/transport-native-unix-common/src/main/c/netty_unix_util.h @@ -18,6 +18,7 @@ #define NETTY_UNIX_UTIL_H_ #include +#include #include #if defined(__MACH__) && !defined(CLOCK_REALTIME) @@ -64,6 +65,20 @@ jboolean netty_unix_util_initialize_wait_clock(clockid_t* clockId); */ int netty_unix_util_clock_gettime(clockid_t clockId, struct timespec* tp); +/** + * Calculate the number of nano seconds elapsed between begin and end. + * + * Returns the number of nano seconds. + */ +uint64_t netty_unix_util_timespec_elapsed_ns(const struct timespec* begin, const struct timespec* end); + +/** + * Subtract
nanos
nano seconds from a
timespec
. + * + * Returns true if there is underflow. + */ +jboolean netty_unix_util_timespec_subtract_ns(struct timespec* ts, uint64_t nanos); + /** * Return type is as defined in http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp5833. */