OSDN Git Service

3a44dd9666b9b7b4769b88277dbe3b7d3a97a057
[pf3gnuchains/gcc-fork.git] / libgfortran / intrinsics / system_clock.c
1 /* Implementation of the SYSTEM_CLOCK intrinsic.
2    Copyright (C) 2004, 2005, 2007, 2009, 2010, 2011 Free Software
3    Foundation, Inc.
4
5 This file is part of the GNU Fortran runtime library (libgfortran).
6
7 Libgfortran is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either
10 version 3 of the License, or (at your option) any later version.
11
12 Libgfortran is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
20
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24 <http://www.gnu.org/licenses/>.  */
25
26 #include "libgfortran.h"
27
28 #include <limits.h>
29
30 #include "time_1.h"
31
32 #ifdef HAVE_CLOCK_GETTIME
33 /* POSIX states that CLOCK_REALTIME must be present if clock_gettime
34    is available, others are optional.  */
35 #ifdef CLOCK_MONOTONIC
36 #define GF_CLOCK_MONOTONIC CLOCK_MONOTONIC
37 #else
38 #define GF_CLOCK_MONOTONIC CLOCK_REALTIME
39 #endif
40
41 /* Weakref trickery for clock_gettime().  On Glibc, clock_gettime()
42    requires us to link in librt, which also pulls in libpthread.  In
43    order to avoid this by default, only call clock_gettime() through a
44    weak reference. 
45
46    Some targets don't support weak undefined references; on these
47    GTHREAD_USE_WEAK is 0. So we need to define it to 1 on other
48    targets.  */
49 #ifndef GTHREAD_USE_WEAK
50 #define GTHREAD_USE_WEAK 1
51 #endif
52
53 #if SUPPORTS_WEAK && GTHREAD_USE_WEAK
54 static int weak_gettime (clockid_t, struct timespec *) 
55   __attribute__((__weakref__("clock_gettime")));
56 #else
57 static inline int weak_gettime (clockid_t clk_id, struct timespec *res)
58 {
59   return clock_gettime (clk_id, res);
60 }
61 #endif
62 #endif
63
64
65 /* High resolution monotonic clock, falling back to the realtime clock
66    if the target does not support such a clock.
67
68    Arguments:
69    secs     - OUTPUT, seconds
70    nanosecs - OUTPUT, nanoseconds
71
72    If the target supports a monotonic clock, the OUTPUT arguments
73    represent a monotonically incrementing clock starting from some
74    unspecified time in the past.
75
76    If a monotonic clock is not available, falls back to the realtime
77    clock which is not monotonic.
78
79    Return value: 0 for success, -1 for error. In case of error, errno
80    is set.
81 */
82 static inline int
83 gf_gettime_mono (time_t * secs, long * nanosecs)
84 {
85   int err;
86 #ifdef HAVE_CLOCK_GETTIME
87   if (weak_gettime)
88     {
89       struct timespec ts;
90       err = weak_gettime (GF_CLOCK_MONOTONIC, &ts);
91       *secs = ts.tv_sec;
92       *nanosecs = ts.tv_nsec;
93       return err;
94     }
95 #endif
96   err = gf_gettime (secs, nanosecs);
97   *nanosecs *= 1000;
98   return err;
99 }
100
101 extern void system_clock_4 (GFC_INTEGER_4 *, GFC_INTEGER_4 *, GFC_INTEGER_4 *);
102 export_proto(system_clock_4);
103
104 extern void system_clock_8 (GFC_INTEGER_8 *, GFC_INTEGER_8 *, GFC_INTEGER_8 *);
105 export_proto(system_clock_8);
106
107
108 /* prefix(system_clock_4) is the INTEGER(4) version of the SYSTEM_CLOCK
109    intrinsic subroutine.  It returns the number of clock ticks for the current
110    system time, the number of ticks per second, and the maximum possible value
111    for COUNT.  On the first call to SYSTEM_CLOCK, COUNT is set to zero. */
112
113 void
114 system_clock_4(GFC_INTEGER_4 *count, GFC_INTEGER_4 *count_rate,
115                GFC_INTEGER_4 *count_max)
116 {
117 #undef TCK
118 #define TCK 1000
119   GFC_INTEGER_4 cnt;
120   GFC_INTEGER_4 mx;
121
122   time_t secs;
123   long nanosecs;
124
125   if (sizeof (secs) < sizeof (GFC_INTEGER_4))
126     internal_error (NULL, "secs too small");
127
128   if (gf_gettime_mono (&secs, &nanosecs) == 0)
129     {
130       GFC_UINTEGER_4 ucnt = (GFC_UINTEGER_4) secs * TCK;
131       ucnt += (nanosecs + 500000000 / TCK) / (1000000000 / TCK);
132       if (ucnt > GFC_INTEGER_4_HUGE)
133         cnt = ucnt - GFC_INTEGER_4_HUGE - 1;
134       else
135         cnt = ucnt;
136       mx = GFC_INTEGER_4_HUGE;
137     }
138   else
139     {
140       if (count != NULL)
141         *count = - GFC_INTEGER_4_HUGE;
142       if (count_rate != NULL)
143         *count_rate = 0;
144       if (count_max != NULL)
145         *count_max = 0;
146       return;
147     }
148
149   if (count != NULL)
150     *count = cnt;
151   if (count_rate != NULL)
152     *count_rate = TCK;
153   if (count_max != NULL)
154     *count_max = mx;
155 }
156
157
158 /* INTEGER(8) version of the above routine.  */
159
160 void
161 system_clock_8 (GFC_INTEGER_8 *count, GFC_INTEGER_8 *count_rate,
162                 GFC_INTEGER_8 *count_max)
163 {
164 #undef TCK
165 #define TCK 1000000000
166   GFC_INTEGER_8 cnt;
167   GFC_INTEGER_8 mx;
168
169   time_t secs;
170   long nanosecs;
171
172   if (sizeof (secs) < sizeof (GFC_INTEGER_4))
173     internal_error (NULL, "secs too small");
174
175   if (gf_gettime_mono (&secs, &nanosecs) == 0)
176     {
177       GFC_UINTEGER_8 ucnt = (GFC_UINTEGER_8) secs * TCK;
178       ucnt += (nanosecs + 500000000 / TCK) / (1000000000 / TCK);
179       if (ucnt > GFC_INTEGER_8_HUGE)
180         cnt = ucnt - GFC_INTEGER_8_HUGE - 1;
181       else
182         cnt = ucnt;
183       mx = GFC_INTEGER_8_HUGE;
184     }
185   else
186     {
187       if (count != NULL)
188         *count = - GFC_INTEGER_8_HUGE;
189       if (count_rate != NULL)
190         *count_rate = 0;
191       if (count_max != NULL)
192         *count_max = 0;
193
194       return;
195     }
196
197   if (count != NULL)
198     *count = cnt;
199   if (count_rate != NULL)
200     *count_rate = TCK;
201   if (count_max != NULL)
202     *count_max = mx;
203 }