system_clock.c 6.4 KB

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