su_time0.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. * This file is part of the Sofia-SIP package
  3. *
  4. * Copyright (C) 2005 Nokia Corporation.
  5. *
  6. * Contact: Pekka Pessi <pekka.pessi@nokia.com>
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public License
  10. * as published by the Free Software Foundation; either version 2.1 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  21. * 02110-1301 USA
  22. *
  23. */
  24. /**@ingroup su_time
  25. * @CFILE su_time0.c
  26. * @brief su_time() implementation
  27. *
  28. * The file su_time0.c contains implementation of OS-independent wallclock
  29. * time with microsecond resolution.
  30. *
  31. * @author Pekka Pessi <Pekka.Pessi@nokia.com>
  32. * @author Jari Selin <Jari.Selin@nokia.com>
  33. *
  34. * @date Created: Fri May 10 18:13:19 2002 ppessi
  35. */
  36. #include "config.h"
  37. #include <stdio.h>
  38. #include <stdlib.h>
  39. #include "sofia-sip/su_types.h"
  40. #include "sofia-sip/su_time.h"
  41. #include "su_module_debug.h"
  42. #include <time.h>
  43. #if HAVE_SYS_TIME_H
  44. #include <sys/time.h> /* Get struct timeval */
  45. #endif
  46. #if defined(__MINGW32__)
  47. #define HAVE_FILETIME 1
  48. #include <windows.h>
  49. #endif
  50. #if HAVE_FILETIME
  51. #define HAVE_FILETIME 1
  52. #include <windows.h>
  53. #endif
  54. /** Seconds from 1.1.1900 to 1.1.1970 */
  55. #define NTP_EPOCH 2208988800UL
  56. #define E9 (1000000000U)
  57. #define E7 (10000000U)
  58. /* Hooks for testing timing and timers */
  59. void (*_su_time)(su_time_t *tv);
  60. uint64_t (*_su_nanotime)(uint64_t *);
  61. static su_time_func_t custom_time_func = NULL;
  62. void su_set_time_func(su_time_func_t func) {
  63. custom_time_func = func;
  64. }
  65. /** Get current time.
  66. *
  67. * The function @c su_time() fills its argument with the current NTP
  68. * timestamp expressed as a su_time_t structure.
  69. *
  70. * @param tv pointer to the timeval object
  71. */
  72. void su_time(su_time_t *tv)
  73. {
  74. #if HAVE_FILETIME
  75. union {
  76. FILETIME ft[1];
  77. ULARGE_INTEGER ull[1];
  78. } date;
  79. #endif
  80. su_time_t ltv = {0,0};
  81. if (custom_time_func) {
  82. custom_time_func(&ltv);
  83. if (tv) *tv = ltv;
  84. return;
  85. }
  86. #if HAVE_CLOCK_GETTIME
  87. struct timespec ctv = {0};
  88. if (clock_gettime(CLOCK_REALTIME, &ctv) == 0) {
  89. ltv.tv_sec = ctv.tv_sec + NTP_EPOCH;
  90. ltv.tv_usec = ctv.tv_nsec / 1000;
  91. }
  92. #elif HAVE_GETTIMEOFDAY
  93. struct timeval tmp_tv = {0,0};
  94. gettimeofday(&tmp_tv, NULL);
  95. ltv.tv_sec = tmp_tv.tv_sec + NTP_EPOCH;
  96. ltv.tv_usec = (unsigned long)tmp_tv.tv_usec;
  97. #elif HAVE_FILETIME
  98. GetSystemTimeAsFileTime(date.ft);
  99. ltv.tv_usec = (unsigned long) ((date.ull->QuadPart % E7) / 10);
  100. ltv.tv_sec = (unsigned long) ((date.ull->QuadPart / E7) -
  101. /* 1900-Jan-01 - 1601-Jan-01: 299 years, 72 leap years */
  102. (299 * 365 + 72) * 24 * 60 * (uint64_t)60);
  103. #else
  104. #error no su_time() implementation
  105. #endif
  106. if (_su_time)
  107. _su_time(&ltv);
  108. if (tv) *tv = ltv;
  109. }
  110. /** Get current time as nanoseconds since epoch.
  111. *
  112. * Return the current NTP timestamp expressed as nanoseconds since epoch
  113. * (January 1st 1900).
  114. *
  115. * @param return_time optional pointer to current time to return
  116. *
  117. * @return Nanoseconds since epoch
  118. */
  119. su_nanotime_t su_nanotime(su_nanotime_t *return_time)
  120. {
  121. su_nanotime_t now;
  122. if (!return_time)
  123. return_time = &now;
  124. #if HAVE_CLOCK_GETTIME
  125. {
  126. struct timespec tv = {0,0};
  127. if (clock_gettime(CLOCK_REALTIME, &tv) == 0) {
  128. now = ((su_nanotime_t)tv.tv_sec + NTP_EPOCH) * E9 + tv.tv_nsec;
  129. *return_time = now;
  130. if (_su_nanotime)
  131. return _su_nanotime(return_time);
  132. return now;
  133. }
  134. }
  135. #endif
  136. #if HAVE_FILETIME
  137. {
  138. union {
  139. FILETIME ft[1];
  140. ULARGE_INTEGER ull[1];
  141. } date;
  142. GetSystemTimeAsFileTime(date.ft);
  143. now = 100 *
  144. (date.ull->QuadPart -
  145. /* 1900-Jan-01 - 1601-Jan-01: 299 years, 72 leap years */
  146. ((su_nanotime_t)(299 * 365 + 72) * 24 * 60 * 60) * E7);
  147. }
  148. #elif HAVE_GETTIMEOFDAY
  149. {
  150. struct timeval tv = {0,0};
  151. gettimeofday(&tv, NULL);
  152. now = ((su_nanotime_t)tv.tv_sec + NTP_EPOCH) * E9 + tv.tv_usec * 1000;
  153. }
  154. #else
  155. now = ((su_nanotime_t)time() + NTP_EPOCH) * E9;
  156. #endif
  157. *return_time = now;
  158. if (_su_nanotime)
  159. return _su_nanotime(return_time);
  160. return now;
  161. }
  162. /** Get current time as nanoseconds.
  163. *
  164. * Return the current time expressed as nanoseconds. The time returned is
  165. * monotonic and never goes back - if the underlying system supports such a
  166. * clock.
  167. *
  168. * @param return_time optional pointer to return the current time
  169. *
  170. * @return Current time as nanoseconds
  171. */
  172. su_nanotime_t su_monotime(su_nanotime_t *return_time)
  173. {
  174. #if HAVE_CLOCK_GETTIME && CLOCK_MONOTONIC
  175. {
  176. struct timespec tv = {0,0};
  177. if (clock_gettime(CLOCK_MONOTONIC, &tv) == 0) {
  178. su_nanotime_t now = (su_nanotime_t)tv.tv_sec * E9 + tv.tv_nsec;
  179. if (return_time)
  180. *return_time = now;
  181. return now;
  182. }
  183. }
  184. #endif
  185. #if HAVE_NANOUPTIME
  186. {
  187. struct timespec tv = {0,0};
  188. nanouptime(&tv);
  189. now = (su_nanotime_t)tv.tv_sec * E9 + tv.tv_nsec;
  190. if (return_time)
  191. *return_time = now;
  192. return now;
  193. }
  194. #elif HAVE_MICROUPTIME
  195. {
  196. struct timeval tv = {0,0};
  197. microuptime(&tv);
  198. now = (su_nanotime_t)tv.tv_sec * E9 + tv.tv_usec * 1000;
  199. if (return_time)
  200. *return_time = now;
  201. return now;
  202. }
  203. #else
  204. return su_nanotime(return_time);
  205. #endif
  206. }