1181254a7Smrg /* Implementation of the SYSTEM_CLOCK intrinsic.
2*b1e83836Smrg Copyright (C) 2004-2022 Free Software Foundation, Inc.
3181254a7Smrg
4181254a7Smrg This file is part of the GNU Fortran runtime library (libgfortran).
5181254a7Smrg
6181254a7Smrg Libgfortran is free software; you can redistribute it and/or
7181254a7Smrg modify it under the terms of the GNU General Public
8181254a7Smrg License as published by the Free Software Foundation; either
9181254a7Smrg version 3 of the License, or (at your option) any later version.
10181254a7Smrg
11181254a7Smrg Libgfortran is distributed in the hope that it will be useful,
12181254a7Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
13181254a7Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14181254a7Smrg GNU General Public License for more details.
15181254a7Smrg
16181254a7Smrg Under Section 7 of GPL version 3, you are granted additional
17181254a7Smrg permissions described in the GCC Runtime Library Exception, version
18181254a7Smrg 3.1, as published by the Free Software Foundation.
19181254a7Smrg
20181254a7Smrg You should have received a copy of the GNU General Public License and
21181254a7Smrg a copy of the GCC Runtime Library Exception along with this program;
22181254a7Smrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23181254a7Smrg <http://www.gnu.org/licenses/>. */
24181254a7Smrg
25181254a7Smrg #include "libgfortran.h"
26181254a7Smrg
27181254a7Smrg #include <limits.h>
28181254a7Smrg
29181254a7Smrg #include "time_1.h"
30181254a7Smrg
31181254a7Smrg
32181254a7Smrg #if !defined(__MINGW32__)
33181254a7Smrg
34181254a7Smrg /* POSIX states that CLOCK_REALTIME must be present if clock_gettime
35181254a7Smrg is available, others are optional. */
36181254a7Smrg #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_GETTIME_LIBRT)
37181254a7Smrg #if defined(CLOCK_MONOTONIC) && defined(_POSIX_MONOTONIC_CLOCK) \
38181254a7Smrg && _POSIX_MONOTONIC_CLOCK >= 0
39181254a7Smrg #define GF_CLOCK_MONOTONIC CLOCK_MONOTONIC
40181254a7Smrg #else
41181254a7Smrg #define GF_CLOCK_MONOTONIC CLOCK_REALTIME
42181254a7Smrg #endif
43181254a7Smrg #endif
44181254a7Smrg
45181254a7Smrg /* Weakref trickery for clock_gettime(). On Glibc <= 2.16,
46181254a7Smrg clock_gettime() requires us to link in librt, which also pulls in
47181254a7Smrg libpthread. In order to avoid this by default, only call
48181254a7Smrg clock_gettime() through a weak reference. */
49181254a7Smrg #if SUPPORTS_WEAKREF && defined(HAVE_CLOCK_GETTIME_LIBRT)
50181254a7Smrg static int weak_gettime (clockid_t, struct timespec *)
51181254a7Smrg __attribute__((__weakref__("clock_gettime")));
52181254a7Smrg #endif
53181254a7Smrg
54181254a7Smrg
55181254a7Smrg /* High resolution monotonic clock, falling back to the realtime clock
56181254a7Smrg if the target does not support such a clock.
57181254a7Smrg
58181254a7Smrg Arguments:
59181254a7Smrg secs - OUTPUT, seconds
60181254a7Smrg fracsecs - OUTPUT, fractional seconds, units given by tk argument
61181254a7Smrg tk - OUTPUT, clock resolution [counts/sec]
62181254a7Smrg
63181254a7Smrg If the target supports a monotonic clock, the OUTPUT arguments
64181254a7Smrg represent a monotonically incrementing clock starting from some
65181254a7Smrg unspecified time in the past.
66181254a7Smrg
67181254a7Smrg If a monotonic clock is not available, falls back to the realtime
68181254a7Smrg clock which is not monotonic.
69181254a7Smrg
70181254a7Smrg Return value: 0 for success, -1 for error. In case of error, errno
71181254a7Smrg is set.
72181254a7Smrg */
73181254a7Smrg static int
gf_gettime_mono(time_t * secs,long * fracsecs,long * tck)74181254a7Smrg gf_gettime_mono (time_t * secs, long * fracsecs, long * tck)
75181254a7Smrg {
76181254a7Smrg int err;
77181254a7Smrg #ifdef HAVE_CLOCK_GETTIME
78181254a7Smrg struct timespec ts;
79181254a7Smrg *tck = 1000000000;
80181254a7Smrg err = clock_gettime (GF_CLOCK_MONOTONIC, &ts);
81181254a7Smrg *secs = ts.tv_sec;
82181254a7Smrg *fracsecs = ts.tv_nsec;
83181254a7Smrg return err;
84181254a7Smrg #else
85181254a7Smrg #if SUPPORTS_WEAKREF && defined(HAVE_CLOCK_GETTIME_LIBRT)
86181254a7Smrg if (weak_gettime)
87181254a7Smrg {
88181254a7Smrg struct timespec ts;
89181254a7Smrg *tck = 1000000000;
90181254a7Smrg err = weak_gettime (GF_CLOCK_MONOTONIC, &ts);
91181254a7Smrg *secs = ts.tv_sec;
92181254a7Smrg *fracsecs = ts.tv_nsec;
93181254a7Smrg return err;
94181254a7Smrg }
95181254a7Smrg #endif
96181254a7Smrg *tck = 1000000;
97181254a7Smrg err = gf_gettime (secs, fracsecs);
98181254a7Smrg return err;
99181254a7Smrg #endif
100181254a7Smrg }
101181254a7Smrg
102181254a7Smrg #endif /* !__MINGW32__ */
103181254a7Smrg
104181254a7Smrg extern void
105181254a7Smrg system_clock_4 (GFC_INTEGER_4 *count, GFC_INTEGER_4 *count_rate,
106181254a7Smrg GFC_INTEGER_4 *count_max);
107181254a7Smrg export_proto(system_clock_4);
108181254a7Smrg
109181254a7Smrg extern void
110181254a7Smrg system_clock_8 (GFC_INTEGER_8 *count, GFC_INTEGER_8 *count_rate,
111181254a7Smrg GFC_INTEGER_8 *count_max);
112181254a7Smrg export_proto(system_clock_8);
113181254a7Smrg
114181254a7Smrg
115181254a7Smrg /* prefix(system_clock_4) is the INTEGER(4) version of the SYSTEM_CLOCK
116181254a7Smrg intrinsic subroutine. It returns the number of clock ticks for the current
117181254a7Smrg system time, the number of ticks per second, and the maximum possible value
118181254a7Smrg for COUNT. */
119181254a7Smrg
120181254a7Smrg void
system_clock_4(GFC_INTEGER_4 * count,GFC_INTEGER_4 * count_rate,GFC_INTEGER_4 * count_max)121181254a7Smrg system_clock_4 (GFC_INTEGER_4 *count, GFC_INTEGER_4 *count_rate,
122181254a7Smrg GFC_INTEGER_4 *count_max)
123181254a7Smrg {
124181254a7Smrg #if defined(__MINGW32__)
125181254a7Smrg if (count)
126181254a7Smrg {
127181254a7Smrg /* Use GetTickCount here as the resolution and range is
128181254a7Smrg sufficient for the INTEGER(kind=4) version, and
129181254a7Smrg QueryPerformanceCounter has potential issues. */
130181254a7Smrg uint32_t cnt = GetTickCount ();
131181254a7Smrg if (cnt > GFC_INTEGER_4_HUGE)
132181254a7Smrg cnt = cnt - GFC_INTEGER_4_HUGE - 1;
133181254a7Smrg *count = cnt;
134181254a7Smrg }
135181254a7Smrg if (count_rate)
136181254a7Smrg *count_rate = 1000;
137181254a7Smrg if (count_max)
138181254a7Smrg *count_max = GFC_INTEGER_4_HUGE;
139181254a7Smrg #else
140181254a7Smrg time_t secs;
141181254a7Smrg long fracsecs, tck;
142181254a7Smrg
143181254a7Smrg if (gf_gettime_mono (&secs, &fracsecs, &tck) == 0)
144181254a7Smrg {
145181254a7Smrg long tck_out = tck > 1000 ? 1000 : tck;
146181254a7Smrg long tck_r = tck / tck_out;
147181254a7Smrg GFC_UINTEGER_4 ucnt = (GFC_UINTEGER_4) secs * tck_out;
148181254a7Smrg ucnt += fracsecs / tck_r;
149181254a7Smrg if (ucnt > GFC_INTEGER_4_HUGE)
150181254a7Smrg ucnt = ucnt - GFC_INTEGER_4_HUGE - 1;
151181254a7Smrg if (count)
152181254a7Smrg *count = ucnt;
153181254a7Smrg if (count_rate)
154181254a7Smrg *count_rate = tck_out;
155181254a7Smrg if (count_max)
156181254a7Smrg *count_max = GFC_INTEGER_4_HUGE;
157181254a7Smrg }
158181254a7Smrg else
159181254a7Smrg {
160181254a7Smrg if (count)
161181254a7Smrg *count = - GFC_INTEGER_4_HUGE;
162181254a7Smrg if (count_rate)
163181254a7Smrg *count_rate = 0;
164181254a7Smrg if (count_max)
165181254a7Smrg *count_max = 0;
166181254a7Smrg }
167181254a7Smrg #endif
168181254a7Smrg }
169181254a7Smrg
170181254a7Smrg
171181254a7Smrg /* INTEGER(8) version of the above routine. */
172181254a7Smrg
173181254a7Smrg void
system_clock_8(GFC_INTEGER_8 * count,GFC_INTEGER_8 * count_rate,GFC_INTEGER_8 * count_max)174181254a7Smrg system_clock_8 (GFC_INTEGER_8 *count, GFC_INTEGER_8 *count_rate,
175181254a7Smrg GFC_INTEGER_8 *count_max)
176181254a7Smrg {
177181254a7Smrg #if defined(__MINGW32__)
178181254a7Smrg LARGE_INTEGER cnt;
179181254a7Smrg LARGE_INTEGER freq;
180181254a7Smrg bool fail = false;
181181254a7Smrg if (count && !QueryPerformanceCounter (&cnt))
182181254a7Smrg fail = true;
183181254a7Smrg if (count_rate && !QueryPerformanceFrequency (&freq))
184181254a7Smrg fail = true;
185181254a7Smrg if (fail)
186181254a7Smrg {
187181254a7Smrg if (count)
188181254a7Smrg *count = - GFC_INTEGER_8_HUGE;
189181254a7Smrg if (count_rate)
190181254a7Smrg *count_rate = 0;
191181254a7Smrg if (count_max)
192181254a7Smrg *count_max = 0;
193181254a7Smrg }
194181254a7Smrg else
195181254a7Smrg {
196181254a7Smrg if (count)
197181254a7Smrg *count = cnt.QuadPart;
198181254a7Smrg if (count_rate)
199181254a7Smrg *count_rate = freq.QuadPart;
200181254a7Smrg if (count_max)
201181254a7Smrg *count_max = GFC_INTEGER_8_HUGE;
202181254a7Smrg }
203181254a7Smrg #else
204181254a7Smrg time_t secs;
205181254a7Smrg long fracsecs, tck;
206181254a7Smrg
207181254a7Smrg if (gf_gettime_mono (&secs, &fracsecs, &tck) == 0)
208181254a7Smrg {
209181254a7Smrg GFC_UINTEGER_8 ucnt = (GFC_UINTEGER_8) secs * tck;
210181254a7Smrg ucnt += fracsecs;
211181254a7Smrg if (ucnt > GFC_INTEGER_8_HUGE)
212181254a7Smrg ucnt = ucnt - GFC_INTEGER_8_HUGE - 1;
213181254a7Smrg if (count)
214181254a7Smrg *count = ucnt;
215181254a7Smrg if (count_rate)
216181254a7Smrg *count_rate = tck;
217181254a7Smrg if (count_max)
218181254a7Smrg *count_max = GFC_INTEGER_8_HUGE;
219181254a7Smrg }
220181254a7Smrg else
221181254a7Smrg {
222181254a7Smrg if (count)
223181254a7Smrg *count = - GFC_INTEGER_8_HUGE;
224181254a7Smrg if (count_rate)
225181254a7Smrg *count_rate = 0;
226181254a7Smrg if (count_max)
227181254a7Smrg *count_max = 0;
228181254a7Smrg }
229181254a7Smrg #endif
230181254a7Smrg }
231