1 | //===-- DNBTimer.h ----------------------------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // Created by Greg Clayton on 12/13/07. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLDB_TOOLS_DEBUGSERVER_SOURCE_DNBTIMER_H |
14 | #define LLDB_TOOLS_DEBUGSERVER_SOURCE_DNBTIMER_H |
15 | |
16 | #include "DNBDefs.h" |
17 | #include "PThreadMutex.h" |
18 | #include <cstdint> |
19 | #include <memory> |
20 | #include <sys/time.h> |
21 | |
22 | class DNBTimer { |
23 | public: |
24 | // Constructors and Destructors |
25 | DNBTimer(bool threadSafe) : m_mutexAP() { |
26 | if (threadSafe) |
27 | m_mutexAP.reset(p: new PThreadMutex(PTHREAD_MUTEX_RECURSIVE)); |
28 | Reset(); |
29 | } |
30 | |
31 | DNBTimer(const DNBTimer &rhs) : m_mutexAP() { |
32 | // Create a new mutex to make this timer thread safe as well if |
33 | // the timer we are copying is thread safe |
34 | if (rhs.IsThreadSafe()) |
35 | m_mutexAP.reset(p: new PThreadMutex(PTHREAD_MUTEX_RECURSIVE)); |
36 | m_timeval = rhs.m_timeval; |
37 | } |
38 | |
39 | DNBTimer &operator=(const DNBTimer &rhs) { |
40 | // Create a new mutex to make this timer thread safe as well if |
41 | // the timer we are copying is thread safe |
42 | if (rhs.IsThreadSafe()) |
43 | m_mutexAP.reset(p: new PThreadMutex(PTHREAD_MUTEX_RECURSIVE)); |
44 | m_timeval = rhs.m_timeval; |
45 | return *this; |
46 | } |
47 | |
48 | ~DNBTimer() {} |
49 | |
50 | bool IsThreadSafe() const { return m_mutexAP.get() != NULL; } |
51 | // Reset the time value to now |
52 | void Reset() { |
53 | PTHREAD_MUTEX_LOCKER(locker, m_mutexAP.get()); |
54 | gettimeofday(tv: &m_timeval, NULL); |
55 | } |
56 | // Get the total microseconds since Jan 1, 1970 |
57 | uint64_t TotalMicroSeconds() const { |
58 | PTHREAD_MUTEX_LOCKER(locker, m_mutexAP.get()); |
59 | return (uint64_t)(m_timeval.tv_sec) * 1000000ull + |
60 | (uint64_t)m_timeval.tv_usec; |
61 | } |
62 | |
63 | void GetTime(uint64_t &sec, uint32_t &usec) const { |
64 | PTHREAD_MUTEX_LOCKER(locker, m_mutexAP.get()); |
65 | sec = m_timeval.tv_sec; |
66 | usec = m_timeval.tv_usec; |
67 | } |
68 | // Return the number of microseconds elapsed between now and the |
69 | // m_timeval |
70 | uint64_t ElapsedMicroSeconds(bool update) { |
71 | PTHREAD_MUTEX_LOCKER(locker, m_mutexAP.get()); |
72 | struct timeval now; |
73 | gettimeofday(tv: &now, NULL); |
74 | uint64_t now_usec = |
75 | (uint64_t)(now.tv_sec) * 1000000ull + (uint64_t)now.tv_usec; |
76 | uint64_t this_usec = |
77 | (uint64_t)(m_timeval.tv_sec) * 1000000ull + (uint64_t)m_timeval.tv_usec; |
78 | uint64_t elapsed = now_usec - this_usec; |
79 | // Update the timer time value if requeseted |
80 | if (update) |
81 | m_timeval = now; |
82 | return elapsed; |
83 | } |
84 | |
85 | static uint64_t GetTimeOfDay() { |
86 | struct timeval now; |
87 | gettimeofday(tv: &now, NULL); |
88 | uint64_t now_usec = |
89 | (uint64_t)(now.tv_sec) * 1000000ull + (uint64_t)now.tv_usec; |
90 | return now_usec; |
91 | } |
92 | |
93 | static void OffsetTimeOfDay(struct timespec *ts, |
94 | __darwin_time_t sec_offset = 0, |
95 | long nsec_offset = 0) { |
96 | if (ts == NULL) |
97 | return; |
98 | // Get the current time in a timeval structure |
99 | struct timeval now; |
100 | gettimeofday(tv: &now, NULL); |
101 | // Morph it into a timespec |
102 | TIMEVAL_TO_TIMESPEC(&now, ts); |
103 | // Offset the timespec if requested |
104 | if (sec_offset != 0 || nsec_offset != 0) { |
105 | // Offset the nano seconds |
106 | ts->tv_nsec += nsec_offset; |
107 | // Offset the seconds taking into account a nano-second overflow |
108 | ts->tv_sec = ts->tv_sec + ts->tv_nsec / 1000000000 + sec_offset; |
109 | // Trim the nanoseconds back there was an overflow |
110 | ts->tv_nsec = ts->tv_nsec % 1000000000; |
111 | } |
112 | } |
113 | static bool TimeOfDayLaterThan(struct timespec &ts) { |
114 | struct timespec now; |
115 | OffsetTimeOfDay(&now); |
116 | if (now.tv_sec > ts.tv_sec) |
117 | return true; |
118 | else if (now.tv_sec < ts.tv_sec) |
119 | return false; |
120 | else { |
121 | if (now.tv_nsec > ts.tv_nsec) |
122 | return true; |
123 | else |
124 | return false; |
125 | } |
126 | } |
127 | |
128 | protected: |
129 | // Classes that inherit from DNBTimer can see and modify these |
130 | std::unique_ptr<PThreadMutex> m_mutexAP; |
131 | struct timeval m_timeval; |
132 | }; |
133 | |
134 | #endif // LLDB_TOOLS_DEBUGSERVER_SOURCE_DNBTIMER_H |
135 | |