Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@

dnl Initialise libtool
AC_DISABLE_STATIC
AC_PROG_LIBTOOL

Check warning on line 252 in configure.ac

View workflow job for this annotation

GitHub Actions / openjdk8-linux

The macro `AC_PROG_LIBTOOL' is obsolete.

Check warning on line 252 in configure.ac

View workflow job for this annotation

GitHub Actions / classpath-macos

The macro 'AC_PROG_LIBTOOL' is obsolete.

Check warning on line 252 in configure.ac

View workflow job for this annotation

GitHub Actions / openjdk8-macos

The macro 'AC_PROG_LIBTOOL' is obsolete.

dnl Checks for programs.
AC_PROG_CC
Expand Down Expand Up @@ -292,6 +292,7 @@

AC_CHECK_LIB(rt,clock_gettime,,)
AC_CHECK_FUNCS([clock_gettime])
AC_CHECK_FUNCS([pthread_condattr_setclock])

AC_CHECK_LIB(m,fmod,,AC_MSG_ERROR(libm is missing))

Expand All @@ -308,7 +309,7 @@
fi

dnl Checks for header files.
AC_HEADER_STDC

Check warning on line 312 in configure.ac

View workflow job for this annotation

GitHub Actions / openjdk8-linux

The macro `AC_HEADER_STDC' is obsolete.

Check warning on line 312 in configure.ac

View workflow job for this annotation

GitHub Actions / classpath-macos

The macro 'AC_HEADER_STDC' is obsolete.

Check warning on line 312 in configure.ac

View workflow job for this annotation

GitHub Actions / openjdk8-macos

The macro 'AC_HEADER_STDC' is obsolete.
AC_CHECK_HEADERS(sys/time.h unistd.h endian.h sys/param.h locale.h alloca.h fenv.h)

if test "$enable_zip" != no; then
Expand Down Expand Up @@ -345,13 +346,13 @@

dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_HEADER_TIME

Check warning on line 349 in configure.ac

View workflow job for this annotation

GitHub Actions / openjdk8-linux

The macro `AC_HEADER_TIME' is obsolete.

Check warning on line 349 in configure.ac

View workflow job for this annotation

GitHub Actions / classpath-macos

The macro 'AC_HEADER_TIME' is obsolete.

Check warning on line 349 in configure.ac

View workflow job for this annotation

GitHub Actions / openjdk8-macos

The macro 'AC_HEADER_TIME' is obsolete.

dnl Checks for library functions.
AC_FUNC_ALLOCA
AC_FUNC_MMAP
AC_CHECK_FUNCS(gettimeofday strtol setlocale)
AM_LC_MESSAGES

Check warning on line 355 in configure.ac

View workflow job for this annotation

GitHub Actions / openjdk8-linux

The macro `AC_TRY_LINK' is obsolete.

Check warning on line 355 in configure.ac

View workflow job for this annotation

GitHub Actions / classpath-macos

The macro 'AC_TRY_LINK' is obsolete.

Check warning on line 355 in configure.ac

View workflow job for this annotation

GitHub Actions / openjdk8-macos

The macro 'AC_TRY_LINK' is obsolete.

dnl This check initially determined if thread local storage is supported by
dnl trying to compile and link a program that uses TLS. However, on several
Expand Down
13 changes: 1 addition & 12 deletions src/classlib/openjdk/jvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,6 @@

#define JVM_INTERFACE_VERSION 4

/* We use the monotonic clock if it is available. As the clock_id may be
present but not actually supported, we check it on startup */
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
static int have_monotonic_clock;
#endif

static Class *cloneable_class, *constant_pool_class;
static Class *exception_class, *runtime_excp_class;

Expand All @@ -72,11 +66,6 @@ static int constant_pool_oop_offset;
int initialiseJVMInterface() {
Class *pae_class;

#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
struct timespec ts;
have_monotonic_clock = (clock_gettime(CLOCK_MONOTONIC, &ts) != -1);
#endif

cloneable_class = findSystemClass0(SYMBOL(java_lang_Cloneable));
constant_pool_class = findSystemClass0(SYMBOL(sun_reflect_ConstantPool));
exception_class = findSystemClass0(SYMBOL(java_lang_Exception));
Expand Down Expand Up @@ -176,7 +165,7 @@ jlong JVM_NanoTime(JNIEnv *env, jclass ignored) {
TRACE("JVM_NanoTime(env=%p, ignored=%p)", env, ignored);

#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
if(have_monotonic_clock) {
if(haveMonotonicClock()) {
struct timespec ts;

clock_gettime(CLOCK_MONOTONIC, &ts);
Expand Down
1 change: 1 addition & 0 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ int initVM(InitArgs *args) {

status = initialiseHooks(args) &&
initialiseProperties(args) &&
initialiseTime() &&
initialiseAlloc(args) &&
initialiseThreadStage1(args) &&
initialiseUtf8() &&
Expand Down
4 changes: 4 additions & 0 deletions src/jam.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <limits.h>
#include <stdio.h>
#include <time.h>
#include <pthread.h>

/* Configure options */
#include "config.h"
Expand Down Expand Up @@ -1300,10 +1301,13 @@ extern int initialiseSymbol();

/* time */

extern int initialiseTime();
extern int haveMonotonicClock();
extern void getTimeoutAbsolute(struct timespec *ts, long long millis,
long long nanos);
extern void getTimeoutRelative(struct timespec *ts, long long millis,
long long nanos);
extern int initReltimeCondVar(pthread_cond_t *cv);

/* sig */

Expand Down
32 changes: 22 additions & 10 deletions src/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,15 +248,19 @@ void threadPark(Thread *self, int absolute, long long time) {
disableSuspend(self);

if(time) {
pthread_cond_t *cv;
struct timespec ts;

if(absolute)
if(absolute) {
getTimeoutAbsolute(&ts, time, 0);
else
cv = &self->park_cv_abs;
} else {
getTimeoutRelative(&ts, 0, time);
cv = &self->park_cv;
}

classlibSetThreadState(self, TIMED_PARKED);
pthread_cond_timedwait(&self->park_cv, &self->park_lock, &ts);
pthread_cond_timedwait(cv, &self->park_lock, &ts);

/* On Linux/i386 systems using LinuxThreads, pthread_cond_timedwait
is implemented using sigjmp/longjmp. This resets the fpu
Expand All @@ -265,6 +269,7 @@ void threadPark(Thread *self, int absolute, long long time) {

FPU_HACK;
} else {
/* Arbitrary choice of condvar when not timed */
classlibSetThreadState(self, PARKED);
pthread_cond_wait(&self->park_cv, &self->park_lock);
}
Expand Down Expand Up @@ -294,11 +299,16 @@ void threadUnpark(Thread *thread) {
/* If another thread has given a permit while we were
waiting for the lock do nothing. Else increase the
state by one (BLOCKED -> RUNNING, RUNNING -> PERMIT)
and if the thread was blocked signal it */
and if the thread was blocked signal it. The thread
waits on park_cv or park_cv_abs depending on the type
of timeout; signalling an un-waited condvar is harmless
and cheap, so simply signal both */

if(thread->park_state != PARK_PERMIT &&
thread->park_state++ == PARK_BLOCKED)
thread->park_state++ == PARK_BLOCKED) {
pthread_cond_signal(&thread->park_cv);
pthread_cond_signal(&thread->park_cv_abs);
}

pthread_mutex_unlock(&thread->park_lock);
}
Expand Down Expand Up @@ -483,12 +493,13 @@ void initThread(Thread *thread, char is_daemon, void *stack_base) {

/* Initialise wait condvar (the condvar is per-thread,
not per-monitor) */
pthread_cond_init(&thread->wait_cv, NULL);
initReltimeCondVar(&thread->wait_cv);

/* Initialise per-thread lock/condvar used for parking
/* Initialise per-thread lock/condvars used for parking
and set initial park state */
thread->park_state = PARK_RUNNING;
pthread_cond_init(&thread->park_cv, NULL);
initReltimeCondVar(&thread->park_cv);
pthread_cond_init(&thread->park_cv_abs, NULL);
pthread_mutex_init(&thread->park_lock, NULL);

/* Record the thread's stack base */
Expand Down Expand Up @@ -1307,10 +1318,11 @@ int initialiseThreadStage1(InitArgs *args) {
initialiseJavaStack(&main_ee);
setThreadSelf(&main_thread);

pthread_cond_init(&main_thread.wait_cv, NULL);
initReltimeCondVar(&main_thread.wait_cv);

main_thread.park_state = PARK_RUNNING;
pthread_cond_init(&main_thread.park_cv, NULL);
initReltimeCondVar(&main_thread.park_cv);
pthread_cond_init(&main_thread.park_cv_abs, NULL);
pthread_mutex_init(&main_thread.park_lock, NULL);

return TRUE;
Expand Down
12 changes: 3 additions & 9 deletions src/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ struct thread {
Thread *wait_next;
pthread_cond_t wait_cv;
pthread_cond_t park_cv;
pthread_cond_t park_cv_abs;
pthread_mutex_t park_lock;
long long blocked_count;
long long waited_count;
Expand Down Expand Up @@ -189,7 +190,7 @@ typedef pthread_mutex_t VMLock;
#define initVMLock(lock) pthread_mutex_init(&lock, NULL)
#define initVMWaitLock(wait_lock) { \
pthread_mutex_init(&wait_lock.lock, NULL); \
pthread_cond_init(&wait_lock.cv, NULL); \
initReltimeCondVar(&wait_lock.cv); \
}

#define lockVMLock(lock, self) { \
Expand All @@ -213,15 +214,8 @@ typedef pthread_mutex_t VMLock;
}

#define timedWaitVMWaitLock(wait_lock, self, ms) { \
struct timeval tv; \
struct timespec ts; \
gettimeofday(&tv, 0); \
ts.tv_sec = tv.tv_sec + ms/1000; \
ts.tv_nsec = (tv.tv_usec + ((ms%1000)*1000))*1000; \
if(ts.tv_nsec > 999999999L) { \
ts.tv_sec++; \
ts.tv_nsec -= 1000000000L; \
} \
getTimeoutRelative(&ts, ms, 0); \
classlibSetThreadState(self, TIMED_WAITING); \
pthread_cond_timedwait(&wait_lock.cv, &wait_lock.lock, &ts); \
classlibSetThreadState(self, RUNNING); \
Expand Down
94 changes: 85 additions & 9 deletions src/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,63 @@
#include <sys/time.h>
#include <time.h>
#include <limits.h>
#include <pthread.h>

#include "jam.h"

#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) && \
defined(HAVE_PTHREAD_CONDATTR_SETCLOCK)
#define MONOTONIC_CONDWAIT
#endif

/* We use the monotonic clock if it is available. As the clock_id may be
present but not actually supported, we check it on startup */
static int have_monotonic_clock = FALSE;

/* For relative timeouts, additionally check that condvars can be bound
to the monotonic clock */
static int have_monotonic_condwait = FALSE;

#ifdef MONOTONIC_CONDWAIT
static pthread_condattr_t monotonic_condattr;
#endif

int initialiseTime() {
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
struct timespec ts;
have_monotonic_clock = (clock_gettime(CLOCK_MONOTONIC, &ts) != -1);

#ifdef MONOTONIC_CONDWAIT
if(have_monotonic_clock &&
pthread_condattr_init(&monotonic_condattr) == 0) {
if(pthread_condattr_setclock(&monotonic_condattr,
CLOCK_MONOTONIC) == 0)
have_monotonic_condwait = TRUE;
else
pthread_condattr_destroy(&monotonic_condattr);
}
#endif
#endif

if(!have_monotonic_condwait)
jam_fprintf(stderr, "Monotonic clock not available. Changes to "
"the current date/time may affect scheduling.\n");

return TRUE;
}

int haveMonotonicClock() {
return have_monotonic_clock;
}

/* Initialise a condition variable to be used for relative timed waits */
int initReltimeCondVar(pthread_cond_t *cv) {
#ifdef MONOTONIC_CONDWAIT
if(have_monotonic_condwait)
return pthread_cond_init(cv, &monotonic_condattr);
#endif
return pthread_cond_init(cv, NULL);
}

void getTimeoutAbsolute(struct timespec *ts, long long millis,
long long nanos) {
Expand All @@ -46,18 +103,36 @@ void getTimeoutAbsolute(struct timespec *ts, long long millis,

void getTimeoutRelative(struct timespec *ts, long long millis,
long long nanos) {
struct timeval tv;
long long seconds;

/* Get the current time */
gettimeofday(&tv, NULL);
#ifdef MONOTONIC_CONDWAIT
if(have_monotonic_condwait) {
struct timespec now;

/* Calculate seconds (long long prevents overflow) */
seconds = tv.tv_sec + millis / 1000 + nanos / 1000000000;
/* Get the current time */
clock_gettime(CLOCK_MONOTONIC, &now);

/* Calculate nanoseconds */
nanos %= 1000000000;
nanos += (tv.tv_usec + ((millis % 1000) * 1000)) * 1000;
/* Calculate seconds (long long prevents overflow) */
seconds = now.tv_sec + millis / 1000 + nanos / 1000000000;

/* Calculate nanoseconds */
nanos %= 1000000000;
nanos += now.tv_nsec + (millis % 1000) * 1000000;
} else
#endif
{
struct timeval tv;

/* Get the current time */
gettimeofday(&tv, NULL);

/* Calculate seconds (long long prevents overflow) */
seconds = tv.tv_sec + millis / 1000 + nanos / 1000000000;

/* Calculate nanoseconds */
nanos %= 1000000000;
nanos += (tv.tv_usec + ((millis % 1000) * 1000)) * 1000;
}

/* Adjust values so that nanos is less than 1 second.
This also prevents overflowing the timespec, as the
Expand All @@ -66,7 +141,8 @@ void getTimeoutRelative(struct timespec *ts, long long millis,
nanos %= 1000000000;

/* If seconds is too big to fit into the timespec use the
maximum value (year 2038) */
maximum value (for 32-bit time_t and realtime clock,
year 2038) */
ts->tv_sec = seconds > LONG_MAX ? LONG_MAX : seconds;
ts->tv_nsec = nanos;
}
Expand Down
Loading