From owner-freebsd-java@freebsd.org Wed Apr 12 17:17:40 2017 Return-Path: Delivered-To: freebsd-java@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 1797ED3B5DE for ; Wed, 12 Apr 2017 17:17:40 +0000 (UTC) (envelope-from jkim@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2610:1c1:1:6074::16:84]) by mx1.freebsd.org (Postfix) with ESMTP id 122E9C11; Wed, 12 Apr 2017 17:17:34 +0000 (UTC) (envelope-from jkim@FreeBSD.org) Subject: Re: OpenJDK8 Thread.sleep will deadlock while turn down system date time. To: Daniel Eischen , Eric van Gyzen Cc: redraiment@gmail.com, Konstantin Belousov , freebsd-java@freebsd.org References: <20170408070340.GD1788@kib.kiev.ua> From: Jung-uk Kim Message-ID: <2349193f-568b-37f1-dcc5-7e0002046325@FreeBSD.org> Date: Wed, 12 Apr 2017 13:17:19 -0400 User-Agent: Mozilla/5.0 (X11; FreeBSD amd64; rv:52.0) Gecko/20100101 Thunderbird/52.0 MIME-Version: 1.0 In-Reply-To: Content-Type: multipart/signed; micalg=pgp-sha256; protocol="application/pgp-signature"; boundary="cV6uTUg3GVSRShqXNSgmnjFCclB7rnd38" X-BeenThere: freebsd-java@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Porting Java to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 12 Apr 2017 17:17:40 -0000 This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --cV6uTUg3GVSRShqXNSgmnjFCclB7rnd38 Content-Type: multipart/mixed; boundary="JqwANXKv1kEpbKlP8nB59T9AmqT6F2xU5"; protected-headers="v1" From: Jung-uk Kim To: Daniel Eischen , Eric van Gyzen Cc: redraiment@gmail.com, Konstantin Belousov , freebsd-java@freebsd.org Message-ID: <2349193f-568b-37f1-dcc5-7e0002046325@FreeBSD.org> Subject: Re: OpenJDK8 Thread.sleep will deadlock while turn down system date time. References: <20170408070340.GD1788@kib.kiev.ua> In-Reply-To: --JqwANXKv1kEpbKlP8nB59T9AmqT6F2xU5 Content-Type: multipart/mixed; boundary="------------3CF86F02B7ADBD7F1FAAA726" Content-Language: en-GB This is a multi-part message in MIME format. --------------3CF86F02B7ADBD7F1FAAA726 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On 04/11/2017 19:55, Daniel Eischen wrote: > On Tue, 11 Apr 2017, Eric van Gyzen wrote: >=20 >> On 4/8/17 2:03 AM, Konstantin Belousov wrote: > [ ... ] >>> >>> If JVM sets timeouts using absolute times than it might be fixed in >>> latest >>> HEAD and stable/11. >> >> The JVM uses pthread_cond_timedwait() to implement Thread.sleep(), so >> it always uses absolute times. Furthermore, it uses the default >> clock, CLOCK_REALTIME. My recent change (r315280) does not fix this >> behavior; in fact, I believe it will make the problem worse, since >> moving the clock forward will wake the thread prematurely. >> >> I think the JVM should be fixed to use CLOCK_MONOTONIC. Would someone= >> like to do the research to determine the correct behavior of >> Thread.sleep()? Specifically, should the duration of the sleep be >> affected by adjustments to the real-time clock? I expect that it >> should /not/ be affected, especially since the API takes a >> relative/interval time. Ideally, we would find the answer in the >> formal language specification; failing that, I would be satisfied with= >> empirical data from testing on Windows, Linux, MacOS, and Solaris.=20 >> I'll be happy to write a patch once we know what it should do. >> >> Please keep me CC'd, since I'm not on freebsd-java@. (Thanks for the >> CC, Kostik.) >=20 > It seems CLOCK_REALTIME behavior has bugged Linux in the past, too. I > think using CLOCK_MONOTONIC, perhaps via pthread_condattr_setclock() in= > our JVM, would be the better approach. http://bugs.java.com/view_bug.do?bug_id=3D6900441 http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/rev/2e6938dd68f2 Basically, it was fixed in Linux source but it wasn't merged to ours somehow. Please try the attached patch. > You'd probably also want to check that whatever java.util.concurrent > relies on, if different, also behaves similarly (monotonically). Runtime behaviour depends on HotSpot implementation. Jung-uk Kim --------------3CF86F02B7ADBD7F1FAAA726 Content-Type: text/x-patch; name="openjdk8.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="openjdk8.diff" Index: java/openjdk8/files/patch-hotspot_src_os_bsd_vm_os__bsd.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- java/openjdk8/files/patch-hotspot_src_os_bsd_vm_os__bsd.cpp (nonexist= ent) +++ java/openjdk8/files/patch-hotspot_src_os_bsd_vm_os__bsd.cpp (working = copy) @@ -0,0 +1,245 @@ +--- hotspot/src/os/bsd/vm/os_bsd.cpp.orig 2017-04-12 17:03:59 UTC ++++ hotspot/src/os/bsd/vm/os_bsd.cpp +@@ -155,6 +155,7 @@ int (*os::Bsd::_getcpuclockid)(pthread_t + #endif + pthread_t os::Bsd::_main_thread; + int os::Bsd::_page_size =3D -1; ++pthread_condattr_t os::Bsd::_condattr[1]; +=20 + static jlong initial_time_count=3D0; +=20 +@@ -1076,12 +1077,15 @@ void os::Bsd::clock_init() { + void os::Bsd::clock_init() { + struct timespec res; + struct timespec tp; ++ _getcpuclockid =3D (int (*)(pthread_t, clockid_t *))dlsym(RTLD_DEFAUL= T, "pthread_getcpuclockid"); + if (::clock_getres(CLOCK_MONOTONIC, &res) =3D=3D 0 && + ::clock_gettime(CLOCK_MONOTONIC, &tp) =3D=3D 0) { + // yes, monotonic clock is supported + _clock_gettime =3D ::clock_gettime; ++ return; + } +- _getcpuclockid =3D (int (*)(pthread_t, clockid_t *))dlsym(RTLD_DEFAUL= T, "pthread_getcpuclockid"); ++ warning("No monotonic clock was available - timed services may " \ ++ "be adversely affected if the time-of-day clock changes"); + } + #endif +=20 +@@ -1117,7 +1121,7 @@ jlong os::javaTimeNanos() { + jlong os::javaTimeNanos() { + if (Bsd::supports_monotonic_clock()) { + struct timespec tp; +- int status =3D Bsd::_clock_gettime(CLOCK_MONOTONIC, &tp); ++ int status =3D ::clock_gettime(CLOCK_MONOTONIC, &tp); + assert(status =3D=3D 0, "gettime error"); + jlong result =3D jlong(tp.tv_sec) * (1000 * 1000 * 1000) + jlong(tp= =2Etv_nsec); + return result; +@@ -3721,6 +3725,25 @@ void os::init(void) { + Bsd::clock_init(); + initial_time_count =3D javaTimeNanos(); +=20 ++ // pthread_condattr initialization for monotonic clock ++ int status; ++ pthread_condattr_t* _condattr =3D os::Bsd::condAttr(); ++ if ((status =3D pthread_condattr_init(_condattr)) !=3D 0) { ++ fatal(err_msg("pthread_condattr_init: %s", strerror(status))); ++ } ++ // Only set the clock if CLOCK_MONOTONIC is available ++ if (Bsd::supports_monotonic_clock()) { ++ if ((status =3D pthread_condattr_setclock(_condattr, CLOCK_MONOTONI= C)) !=3D 0) { ++ if (status =3D=3D EINVAL) { ++ warning("Unable to use monotonic clock with relative timed-wait= s" \ ++ " - changes to the time-of-day clock may have adverse a= ffects"); ++ } else { ++ fatal(err_msg("pthread_condattr_setclock: %s", strerror(status)= )); ++ } ++ } ++ } ++ // else it defaults to CLOCK_REALTIME ++ + #ifdef __APPLE__ + // XXXDARWIN + // Work around the unaligned VM callbacks in hotspot's +@@ -4483,21 +4506,36 @@ void os::pause() { +=20 + static struct timespec* compute_abstime(struct timespec* abstime, jlong= millis) { + if (millis < 0) millis =3D 0; +- struct timeval now; +- int status =3D gettimeofday(&now, NULL); +- assert(status =3D=3D 0, "gettimeofday"); ++ + jlong seconds =3D millis / 1000; + millis %=3D 1000; + if (seconds > 50000000) { // see man cond_timedwait(3T) + seconds =3D 50000000; + } +- abstime->tv_sec =3D now.tv_sec + seconds; +- long usec =3D now.tv_usec + millis * 1000; +- if (usec >=3D 1000000) { +- abstime->tv_sec +=3D 1; +- usec -=3D 1000000; ++ ++ if (os::Bsd::supports_monotonic_clock()) { ++ struct timespec now; ++ int status =3D ::clock_gettime(CLOCK_MONOTONIC, &now); ++ assert_status(status =3D=3D 0, status, "clock_gettime"); ++ abstime->tv_sec =3D now.tv_sec + seconds; ++ long nanos =3D now.tv_nsec + millis * NANOSECS_PER_MILLISEC; ++ if (nanos >=3D NANOSECS_PER_SEC) { ++ abstime->tv_sec +=3D 1; ++ nanos -=3D NANOSECS_PER_SEC; ++ } ++ abstime->tv_nsec =3D nanos; ++ } else { ++ struct timeval now; ++ int status =3D gettimeofday(&now, NULL); ++ assert(status =3D=3D 0, "gettimeofday"); ++ abstime->tv_sec =3D now.tv_sec + seconds; ++ long usec =3D now.tv_usec + millis * 1000; ++ if (usec >=3D 1000000) { ++ abstime->tv_sec +=3D 1; ++ usec -=3D 1000000; ++ } ++ abstime->tv_nsec =3D usec * 1000; + } +- abstime->tv_nsec =3D usec * 1000; + return abstime; + } +=20 +@@ -4589,7 +4627,7 @@ int os::PlatformEvent::park(jlong millis + status =3D os::Bsd::safe_cond_timedwait(_cond, _mutex, &abst); + if (status !=3D 0 && WorkAroundNPTLTimedWaitHang) { + pthread_cond_destroy (_cond); +- pthread_cond_init (_cond, NULL) ; ++ pthread_cond_init (_cond, os::Bsd::condAttr()) ; + } + assert_status(status =3D=3D 0 || status =3D=3D EINTR || + status =3D=3D ETIMEDOUT, +@@ -4690,32 +4728,50 @@ void os::PlatformEvent::unpark() { +=20 + static void unpackTime(struct timespec* absTime, bool isAbsolute, jlong= time) { + assert (time > 0, "convertTime"); ++ time_t max_secs =3D 0; +=20 +- struct timeval now; +- int status =3D gettimeofday(&now, NULL); +- assert(status =3D=3D 0, "gettimeofday"); ++ if (!os::Bsd::supports_monotonic_clock() || isAbsolute) { ++ struct timeval now; ++ int status =3D gettimeofday(&now, NULL); ++ assert(status =3D=3D 0, "gettimeofday"); +=20 +- time_t max_secs =3D now.tv_sec + MAX_SECS; ++ max_secs =3D now.tv_sec + MAX_SECS; +=20 +- if (isAbsolute) { +- jlong secs =3D time / 1000; +- if (secs > max_secs) { +- absTime->tv_sec =3D max_secs; +- } +- else { +- absTime->tv_sec =3D secs; ++ if (isAbsolute) { ++ jlong secs =3D time / 1000; ++ if (secs > max_secs) { ++ absTime->tv_sec =3D max_secs; ++ } else { ++ absTime->tv_sec =3D secs; ++ } ++ absTime->tv_nsec =3D (time % 1000) * NANOSECS_PER_MILLISEC; ++ } else { ++ jlong secs =3D time / NANOSECS_PER_SEC; ++ if (secs >=3D MAX_SECS) { ++ absTime->tv_sec =3D max_secs; ++ absTime->tv_nsec =3D 0; ++ } else { ++ absTime->tv_sec =3D now.tv_sec + secs; ++ absTime->tv_nsec =3D (time % NANOSECS_PER_SEC) + now.tv_usec*10= 00; ++ if (absTime->tv_nsec >=3D NANOSECS_PER_SEC) { ++ absTime->tv_nsec -=3D NANOSECS_PER_SEC; ++ ++absTime->tv_sec; // note: this must be <=3D max_secs ++ } ++ } + } +- absTime->tv_nsec =3D (time % 1000) * NANOSECS_PER_MILLISEC; +- } +- else { ++ } else { ++ // must be relative using monotonic clock ++ struct timespec now; ++ int status =3D ::clock_gettime(CLOCK_MONOTONIC, &now); ++ assert_status(status =3D=3D 0, status, "clock_gettime"); ++ max_secs =3D now.tv_sec + MAX_SECS; + jlong secs =3D time / NANOSECS_PER_SEC; + if (secs >=3D MAX_SECS) { + absTime->tv_sec =3D max_secs; + absTime->tv_nsec =3D 0; +- } +- else { ++ } else { + absTime->tv_sec =3D now.tv_sec + secs; +- absTime->tv_nsec =3D (time % NANOSECS_PER_SEC) + now.tv_usec*1000= ; ++ absTime->tv_nsec =3D (time % NANOSECS_PER_SEC) + now.tv_nsec; + if (absTime->tv_nsec >=3D NANOSECS_PER_SEC) { + absTime->tv_nsec -=3D NANOSECS_PER_SEC; + ++absTime->tv_sec; // note: this must be <=3D max_secs +@@ -4795,15 +4851,19 @@ void Parker::park(bool isAbsolute, jlong + jt->set_suspend_equivalent(); + // cleared by handle_special_suspend_equivalent_condition() or java_s= uspend_self() +=20 ++ assert(_cur_index =3D=3D -1, "invariant"); + if (time =3D=3D 0) { +- status =3D pthread_cond_wait (_cond, _mutex) ; ++ _cur_index =3D REL_INDEX; // arbitrary choice when not timed ++ status =3D pthread_cond_wait (&_cond[_cur_index], _mutex) ; + } else { +- status =3D os::Bsd::safe_cond_timedwait (_cond, _mutex, &absTime) ;= ++ _cur_index =3D isAbsolute ? ABS_INDEX : REL_INDEX; ++ status =3D os::Bsd::safe_cond_timedwait (&_cond[_cur_index], _mutex= , &absTime) ; + if (status !=3D 0 && WorkAroundNPTLTimedWaitHang) { +- pthread_cond_destroy (_cond) ; +- pthread_cond_init (_cond, NULL); ++ pthread_cond_destroy (&_cond[_cur_index]) ; ++ pthread_cond_init (&_cond[_cur_index], isAbsolute ? NULL : os:= :Bsd::condAttr()); + } + } ++ _cur_index =3D -1; + assert_status(status =3D=3D 0 || status =3D=3D EINTR || + status =3D=3D ETIMEDOUT, + status, "cond_timedwait"); +@@ -4832,17 +4892,26 @@ void Parker::unpark() { + s =3D _counter; + _counter =3D 1; + if (s < 1) { +- if (WorkAroundNPTLTimedWaitHang) { +- status =3D pthread_cond_signal (_cond) ; +- assert (status =3D=3D 0, "invariant") ; ++ // thread might be parked ++ if (_cur_index !=3D -1) { ++ // thread is definitely parked ++ if (WorkAroundNPTLTimedWaitHang) { ++ status =3D pthread_cond_signal (&_cond[_cur_index]); ++ assert (status =3D=3D 0, "invariant"); + status =3D pthread_mutex_unlock(_mutex); +- assert (status =3D=3D 0, "invariant") ; +- } else { ++ assert (status =3D=3D 0, "invariant"); ++ } else { ++ // must capture correct index before unlocking ++ int index =3D _cur_index; + status =3D pthread_mutex_unlock(_mutex); +- assert (status =3D=3D 0, "invariant") ; +- status =3D pthread_cond_signal (_cond) ; +- assert (status =3D=3D 0, "invariant") ; +- } ++ assert (status =3D=3D 0, "invariant"); ++ status =3D pthread_cond_signal (&_cond[index]); ++ assert (status =3D=3D 0, "invariant"); ++ } ++ } else { ++ pthread_mutex_unlock(_mutex); ++ assert (status =3D=3D 0, "invariant") ; ++ } + } else { + pthread_mutex_unlock(_mutex); + assert (status =3D=3D 0, "invariant") ; Property changes on: java/openjdk8/files/patch-hotspot_src_os_bsd_vm_os__= bsd.cpp ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: java/openjdk8/files/patch-hotspot_src_os_bsd_vm_os__bsd.hpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- java/openjdk8/files/patch-hotspot_src_os_bsd_vm_os__bsd.hpp (nonexist= ent) +++ java/openjdk8/files/patch-hotspot_src_os_bsd_vm_os__bsd.hpp (working = copy) @@ -0,0 +1,63 @@ +--- hotspot/src/os/bsd/vm/os_bsd.hpp.orig 2017-04-12 15:33:50 UTC ++++ hotspot/src/os/bsd/vm/os_bsd.hpp +@@ -155,6 +155,13 @@ class Bsd { + #endif + } +=20 ++ // pthread_cond clock suppport ++ private: ++ static pthread_condattr_t _condattr[1]; ++ ++ public: ++ static pthread_condattr_t* condAttr() { return _condattr; } ++ + // Stack repair handling +=20 + // none present +@@ -220,7 +227,7 @@ class PlatformEvent : public CHeapObj { + protected: ++ enum { ++ REL_INDEX =3D 0, ++ ABS_INDEX =3D 1 ++ }; ++ int _cur_index; // which cond is in use: -1, 0, 1 + pthread_mutex_t _mutex [1] ; +- pthread_cond_t _cond [1] ; ++ pthread_cond_t _cond [2] ; // one for relative times and one for = abs. +=20 + public: // TODO-FIXME: make dtor private + ~PlatformParker() { guarantee (0, "invariant") ; } +@@ -250,10 +262,13 @@ class PlatformParker : public CHeapObj