Correctly handle overflow in Native.kevent(...) when EINTR is detected (#9024)
Motivation: When kevent(...) returns with EINTR we do not correctly decrement the timespec structure contents to account for the time duration. This may lead to negative values for tv_nsec which will result in an EINVAL and raise an IOException to the event loop selection loop. Modifications: Correctly calculate new timeoutTs when EINTR is detected Result: Fixes #9013.
This commit is contained in:
parent
c0d3444f6d
commit
ac023da16d
@ -139,15 +139,11 @@ static jint netty_kqueue_native_keventWait(JNIEnv* env, jclass clazz, jint kqueu
|
|||||||
}
|
}
|
||||||
|
|
||||||
netty_unix_util_clock_gettime(waitClockId, &nowTs);
|
netty_unix_util_clock_gettime(waitClockId, &nowTs);
|
||||||
// beforeTs will store the time difference to check for overflow
|
if (netty_unix_util_timespec_subtract_ns(&timeoutTs,
|
||||||
beforeTs.tv_sec = nowTs.tv_sec - beforeTs.tv_sec;
|
netty_unix_util_timespec_elapsed_ns(&beforeTs, &nowTs))) {
|
||||||
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)) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeTs = nowTs;
|
beforeTs = nowTs;
|
||||||
// https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
|
// 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.
|
// When kevent() call fails with EINTR error, all changes in the changelist have been applied.
|
||||||
|
@ -19,11 +19,12 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "netty_unix_util.h"
|
#include "netty_unix_util.h"
|
||||||
|
|
||||||
|
static const uint64_t NETTY_BILLION = 1000000000L;
|
||||||
|
|
||||||
#ifdef NETTY_USE_MACH_INSTEAD_OF_CLOCK
|
#ifdef NETTY_USE_MACH_INSTEAD_OF_CLOCK
|
||||||
|
|
||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
#include <mach/mach_time.h>
|
#include <mach/mach_time.h>
|
||||||
static const uint64_t NETTY_BILLION = 1000000000L;
|
|
||||||
|
|
||||||
#endif /* NETTY_USE_MACH_INSTEAD_OF_CLOCK */
|
#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
|
// 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) {
|
int netty_unix_util_clock_gettime(clockid_t clockId, struct timespec* tp) {
|
||||||
#ifdef NETTY_USE_MACH_INSTEAD_OF_CLOCK
|
#ifdef NETTY_USE_MACH_INSTEAD_OF_CLOCK
|
||||||
uint64_t timeNs;
|
uint64_t timeNs;
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#define NETTY_UNIX_UTIL_H_
|
#define NETTY_UNIX_UTIL_H_
|
||||||
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#if defined(__MACH__) && !defined(CLOCK_REALTIME)
|
#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);
|
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 <pre>nanos</pre> nano seconds from a <pre>timespec</pre>.
|
||||||
|
*
|
||||||
|
* 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.
|
* Return type is as defined in http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp5833.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user