clock.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/common/clock.h>
  6. #include <time.h>
  7. static const uint64_t NS_PER_SEC = 1000000000;
  8. #if defined(CLOCK_MONOTONIC_RAW)
  9. # define HIGH_RES_CLOCK CLOCK_MONOTONIC_RAW
  10. #else
  11. # define HIGH_RES_CLOCK CLOCK_MONOTONIC
  12. #endif
  13. /* This entire compilation branch has two goals. First, prior to OSX Sierra, clock_gettime does not exist on OSX, so we
  14. * already need to branch on that. Second, even if we compile on a newer OSX, which we will always do for bindings (e.g.
  15. * python, dotnet, java etc...), we have to worry about the same lib being loaded on an older version, and thus, we'd
  16. * get linker errors at runtime. To avoid this, we do a dynamic load
  17. * to keep the function out of linker tables and only use the symbol if the current running process has access to the
  18. * function. */
  19. #if defined(__MACH__)
  20. # include <AvailabilityMacros.h>
  21. # include <aws/common/thread.h>
  22. # include <dlfcn.h>
  23. # include <sys/time.h>
  24. static int s_legacy_get_time(uint64_t *timestamp) {
  25. struct timeval tv;
  26. int ret_val = gettimeofday(&tv, NULL);
  27. if (ret_val) {
  28. return aws_raise_error(AWS_ERROR_CLOCK_FAILURE);
  29. }
  30. uint64_t secs = (uint64_t)tv.tv_sec;
  31. uint64_t u_secs = (uint64_t)tv.tv_usec;
  32. *timestamp = (secs * NS_PER_SEC) + (u_secs * 1000);
  33. return AWS_OP_SUCCESS;
  34. }
  35. # if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
  36. static aws_thread_once s_thread_once_flag = AWS_THREAD_ONCE_STATIC_INIT;
  37. static int (*s_gettime_fn)(clockid_t __clock_id, struct timespec *__tp) = NULL;
  38. static void s_do_osx_loads(void *user_data) {
  39. (void)user_data;
  40. s_gettime_fn = (int (*)(clockid_t __clock_id, struct timespec * __tp)) dlsym(RTLD_DEFAULT, "clock_gettime");
  41. }
  42. int aws_high_res_clock_get_ticks(uint64_t *timestamp) {
  43. aws_thread_call_once(&s_thread_once_flag, s_do_osx_loads, NULL);
  44. int ret_val = 0;
  45. if (s_gettime_fn) {
  46. struct timespec ts;
  47. ret_val = s_gettime_fn(HIGH_RES_CLOCK, &ts);
  48. if (ret_val) {
  49. return aws_raise_error(AWS_ERROR_CLOCK_FAILURE);
  50. }
  51. uint64_t secs = (uint64_t)ts.tv_sec;
  52. uint64_t n_secs = (uint64_t)ts.tv_nsec;
  53. *timestamp = (secs * NS_PER_SEC) + n_secs;
  54. return AWS_OP_SUCCESS;
  55. }
  56. return s_legacy_get_time(timestamp);
  57. }
  58. int aws_sys_clock_get_ticks(uint64_t *timestamp) {
  59. aws_thread_call_once(&s_thread_once_flag, s_do_osx_loads, NULL);
  60. int ret_val = 0;
  61. if (s_gettime_fn) {
  62. struct timespec ts;
  63. ret_val = s_gettime_fn(CLOCK_REALTIME, &ts);
  64. if (ret_val) {
  65. return aws_raise_error(AWS_ERROR_CLOCK_FAILURE);
  66. }
  67. uint64_t secs = (uint64_t)ts.tv_sec;
  68. uint64_t n_secs = (uint64_t)ts.tv_nsec;
  69. *timestamp = (secs * NS_PER_SEC) + n_secs;
  70. return AWS_OP_SUCCESS;
  71. }
  72. return s_legacy_get_time(timestamp);
  73. }
  74. # else
  75. int aws_high_res_clock_get_ticks(uint64_t *timestamp) {
  76. return s_legacy_get_time(timestamp);
  77. }
  78. int aws_sys_clock_get_ticks(uint64_t *timestamp) {
  79. return s_legacy_get_time(timestamp);
  80. }
  81. # endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 */
  82. /* Everywhere else, just link clock_gettime in directly */
  83. #else
  84. int aws_high_res_clock_get_ticks(uint64_t *timestamp) {
  85. int ret_val = 0;
  86. struct timespec ts;
  87. ret_val = clock_gettime(HIGH_RES_CLOCK, &ts);
  88. if (ret_val) {
  89. return aws_raise_error(AWS_ERROR_CLOCK_FAILURE);
  90. }
  91. uint64_t secs = (uint64_t)ts.tv_sec;
  92. uint64_t n_secs = (uint64_t)ts.tv_nsec;
  93. *timestamp = (secs * NS_PER_SEC) + n_secs;
  94. return AWS_OP_SUCCESS;
  95. }
  96. int aws_sys_clock_get_ticks(uint64_t *timestamp) {
  97. int ret_val = 0;
  98. struct timespec ts;
  99. ret_val = clock_gettime(CLOCK_REALTIME, &ts);
  100. if (ret_val) {
  101. return aws_raise_error(AWS_ERROR_CLOCK_FAILURE);
  102. }
  103. uint64_t secs = (uint64_t)ts.tv_sec;
  104. uint64_t n_secs = (uint64_t)ts.tv_nsec;
  105. *timestamp = (secs * NS_PER_SEC) + n_secs;
  106. return AWS_OP_SUCCESS;
  107. }
  108. #endif /* defined(__MACH__) */