crl_time.cpp 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #include <crl/crl_time.h>
  8. #include <atomic>
  9. #include <ctime>
  10. #include <limits>
  11. namespace crl {
  12. namespace details {
  13. namespace {
  14. time LastAdjustmentTime/* = 0*/;
  15. std::time_t LastAdjustmentUnixtime/* = 0*/;
  16. using seconds_type = std::uint32_t;
  17. std::atomic<seconds_type> AdjustSeconds/* = 0*/;
  18. inner_time_type StartValue/* = 0*/;
  19. inner_profile_type StartProfileValue/* = 0*/;
  20. struct StaticInit {
  21. StaticInit();
  22. };
  23. StaticInit::StaticInit() {
  24. StartValue = current_value();
  25. StartProfileValue = current_profile_value();
  26. init();
  27. LastAdjustmentUnixtime = ::time(nullptr);
  28. }
  29. StaticInit StaticInitObject;
  30. bool adjust_time() {
  31. const auto now = crl::now();
  32. const auto delta = (now - LastAdjustmentTime);
  33. const auto unixtime = ::time(nullptr);
  34. const auto real = (unixtime - LastAdjustmentUnixtime);
  35. const auto seconds = (time(real) * 1000 - delta) / 1000;
  36. LastAdjustmentUnixtime = unixtime;
  37. LastAdjustmentTime = now;
  38. if (seconds <= 0) {
  39. return false;
  40. }
  41. auto current = seconds_type(0);
  42. static constexpr auto max = std::numeric_limits<seconds_type>::max();
  43. while (true) {
  44. if (time(current) + seconds > time(max)) {
  45. return false;
  46. }
  47. const auto next = current + seconds_type(seconds);
  48. if (AdjustSeconds.compare_exchange_weak(current, next)) {
  49. return true;
  50. }
  51. }
  52. return false;
  53. }
  54. time compute_adjustment() {
  55. return time(AdjustSeconds.load()) * 1000;
  56. }
  57. profile_time compute_profile_adjustment() {
  58. return compute_adjustment() * 1000;
  59. }
  60. } // namespace
  61. } // namespace details
  62. time now() {
  63. const auto elapsed = details::current_value() - details::StartValue;
  64. return details::convert(elapsed) + details::compute_adjustment();
  65. }
  66. profile_time profile() {
  67. const auto elapsed = details::current_profile_value()
  68. - details::StartProfileValue;
  69. return details::convert_profile(elapsed)
  70. + details::compute_profile_adjustment();
  71. }
  72. bool adjust_time() {
  73. return details::adjust_time();
  74. }
  75. } // namespace crl