|  | /* Implementation of the SYSTEM_CLOCK intrinsic. | 
|  | Copyright (C) 2004-2021 Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of the GNU Fortran runtime library (libgfortran). | 
|  |  | 
|  | Libgfortran is free software; you can redistribute it and/or | 
|  | modify it under the terms of the GNU General Public | 
|  | License as published by the Free Software Foundation; either | 
|  | version 3 of the License, or (at your option) any later version. | 
|  |  | 
|  | Libgfortran is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | Under Section 7 of GPL version 3, you are granted additional | 
|  | permissions described in the GCC Runtime Library Exception, version | 
|  | 3.1, as published by the Free Software Foundation. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License and | 
|  | a copy of the GCC Runtime Library Exception along with this program; | 
|  | see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see | 
|  | <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | #include "libgfortran.h" | 
|  |  | 
|  | #include <limits.h> | 
|  |  | 
|  | #include "time_1.h" | 
|  |  | 
|  |  | 
|  | #if !defined(__MINGW32__) | 
|  |  | 
|  | /* POSIX states that CLOCK_REALTIME must be present if clock_gettime | 
|  | is available, others are optional.  */ | 
|  | #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_GETTIME_LIBRT) | 
|  | #if defined(CLOCK_MONOTONIC) && defined(_POSIX_MONOTONIC_CLOCK) \ | 
|  | && _POSIX_MONOTONIC_CLOCK >= 0 | 
|  | #define GF_CLOCK_MONOTONIC CLOCK_MONOTONIC | 
|  | #else | 
|  | #define GF_CLOCK_MONOTONIC CLOCK_REALTIME | 
|  | #endif | 
|  | #endif | 
|  |  | 
|  | /* Weakref trickery for clock_gettime().  On Glibc <= 2.16, | 
|  | clock_gettime() requires us to link in librt, which also pulls in | 
|  | libpthread.  In order to avoid this by default, only call | 
|  | clock_gettime() through a weak reference.  */ | 
|  | #if SUPPORTS_WEAKREF && defined(HAVE_CLOCK_GETTIME_LIBRT) | 
|  | static int weak_gettime (clockid_t, struct timespec *) | 
|  | __attribute__((__weakref__("clock_gettime"))); | 
|  | #endif | 
|  |  | 
|  |  | 
|  | /* High resolution monotonic clock, falling back to the realtime clock | 
|  | if the target does not support such a clock. | 
|  |  | 
|  | Arguments: | 
|  | secs     - OUTPUT, seconds | 
|  | fracsecs - OUTPUT, fractional seconds, units given by tk argument | 
|  | tk       - OUTPUT, clock resolution [counts/sec] | 
|  |  | 
|  | If the target supports a monotonic clock, the OUTPUT arguments | 
|  | represent a monotonically incrementing clock starting from some | 
|  | unspecified time in the past. | 
|  |  | 
|  | If a monotonic clock is not available, falls back to the realtime | 
|  | clock which is not monotonic. | 
|  |  | 
|  | Return value: 0 for success, -1 for error. In case of error, errno | 
|  | is set. | 
|  | */ | 
|  | static int | 
|  | gf_gettime_mono (time_t * secs, long * fracsecs, long * tck) | 
|  | { | 
|  | int err; | 
|  | #ifdef HAVE_CLOCK_GETTIME | 
|  | struct timespec ts; | 
|  | *tck = 1000000000; | 
|  | err = clock_gettime (GF_CLOCK_MONOTONIC, &ts); | 
|  | *secs = ts.tv_sec; | 
|  | *fracsecs = ts.tv_nsec; | 
|  | return err; | 
|  | #else | 
|  | #if SUPPORTS_WEAKREF && defined(HAVE_CLOCK_GETTIME_LIBRT) | 
|  | if (weak_gettime) | 
|  | { | 
|  | struct timespec ts; | 
|  | *tck = 1000000000; | 
|  | err = weak_gettime (GF_CLOCK_MONOTONIC, &ts); | 
|  | *secs = ts.tv_sec; | 
|  | *fracsecs = ts.tv_nsec; | 
|  | return err; | 
|  | } | 
|  | #endif | 
|  | *tck = 1000000; | 
|  | err = gf_gettime (secs, fracsecs); | 
|  | return err; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | #endif /* !__MINGW32__  */ | 
|  |  | 
|  | extern void | 
|  | system_clock_4 (GFC_INTEGER_4 *count, GFC_INTEGER_4 *count_rate, | 
|  | GFC_INTEGER_4 *count_max); | 
|  | export_proto(system_clock_4); | 
|  |  | 
|  | extern void | 
|  | system_clock_8 (GFC_INTEGER_8 *count, GFC_INTEGER_8 *count_rate, | 
|  | GFC_INTEGER_8 *count_max); | 
|  | export_proto(system_clock_8); | 
|  |  | 
|  |  | 
|  | /* prefix(system_clock_4) is the INTEGER(4) version of the SYSTEM_CLOCK | 
|  | intrinsic subroutine.  It returns the number of clock ticks for the current | 
|  | system time, the number of ticks per second, and the maximum possible value | 
|  | for COUNT.  */ | 
|  |  | 
|  | void | 
|  | system_clock_4 (GFC_INTEGER_4 *count, GFC_INTEGER_4 *count_rate, | 
|  | GFC_INTEGER_4 *count_max) | 
|  | { | 
|  | #if defined(__MINGW32__) | 
|  | if (count) | 
|  | { | 
|  | /* Use GetTickCount here as the resolution and range is | 
|  | sufficient for the INTEGER(kind=4) version, and | 
|  | QueryPerformanceCounter has potential issues.  */ | 
|  | uint32_t cnt = GetTickCount (); | 
|  | if (cnt > GFC_INTEGER_4_HUGE) | 
|  | cnt = cnt - GFC_INTEGER_4_HUGE - 1; | 
|  | *count = cnt; | 
|  | } | 
|  | if (count_rate) | 
|  | *count_rate = 1000; | 
|  | if (count_max) | 
|  | *count_max = GFC_INTEGER_4_HUGE; | 
|  | #else | 
|  | time_t secs; | 
|  | long fracsecs, tck; | 
|  |  | 
|  | if (gf_gettime_mono (&secs, &fracsecs, &tck) == 0) | 
|  | { | 
|  | long tck_out = tck > 1000 ? 1000 : tck; | 
|  | long tck_r = tck / tck_out; | 
|  | GFC_UINTEGER_4 ucnt = (GFC_UINTEGER_4) secs * tck_out; | 
|  | ucnt += fracsecs / tck_r; | 
|  | if (ucnt > GFC_INTEGER_4_HUGE) | 
|  | ucnt = ucnt - GFC_INTEGER_4_HUGE - 1; | 
|  | if (count) | 
|  | *count = ucnt; | 
|  | if (count_rate) | 
|  | *count_rate = tck_out; | 
|  | if (count_max) | 
|  | *count_max = GFC_INTEGER_4_HUGE; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (count) | 
|  | *count = - GFC_INTEGER_4_HUGE; | 
|  | if (count_rate) | 
|  | *count_rate = 0; | 
|  | if (count_max) | 
|  | *count_max = 0; | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  |  | 
|  | /* INTEGER(8) version of the above routine.  */ | 
|  |  | 
|  | void | 
|  | system_clock_8 (GFC_INTEGER_8 *count, GFC_INTEGER_8 *count_rate, | 
|  | GFC_INTEGER_8 *count_max) | 
|  | { | 
|  | #if defined(__MINGW32__) | 
|  | LARGE_INTEGER cnt; | 
|  | LARGE_INTEGER freq; | 
|  | bool fail = false; | 
|  | if (count && !QueryPerformanceCounter (&cnt)) | 
|  | fail = true; | 
|  | if (count_rate && !QueryPerformanceFrequency (&freq)) | 
|  | fail = true; | 
|  | if (fail) | 
|  | { | 
|  | if (count) | 
|  | *count = - GFC_INTEGER_8_HUGE; | 
|  | if (count_rate) | 
|  | *count_rate = 0; | 
|  | if (count_max) | 
|  | *count_max = 0; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (count) | 
|  | *count = cnt.QuadPart; | 
|  | if (count_rate) | 
|  | *count_rate = freq.QuadPart; | 
|  | if (count_max) | 
|  | *count_max = GFC_INTEGER_8_HUGE; | 
|  | } | 
|  | #else | 
|  | time_t secs; | 
|  | long fracsecs, tck; | 
|  |  | 
|  | if (gf_gettime_mono (&secs, &fracsecs, &tck) == 0) | 
|  | { | 
|  | GFC_UINTEGER_8 ucnt = (GFC_UINTEGER_8) secs * tck; | 
|  | ucnt += fracsecs; | 
|  | if (ucnt > GFC_INTEGER_8_HUGE) | 
|  | ucnt = ucnt - GFC_INTEGER_8_HUGE - 1; | 
|  | if (count) | 
|  | *count = ucnt; | 
|  | if (count_rate) | 
|  | *count_rate = tck; | 
|  | if (count_max) | 
|  | *count_max = GFC_INTEGER_8_HUGE; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (count) | 
|  | *count = - GFC_INTEGER_8_HUGE; | 
|  | if (count_rate) | 
|  | *count_rate = 0; | 
|  | if (count_max) | 
|  | *count_max = 0; | 
|  | } | 
|  | #endif | 
|  | } |