1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stddef.h>
26 #include <sys/time.h>
27
28 #ifdef HAVE_WINDOWS_H
29 #include <windows.h>
30 #endif
31
32 #include <pulsecore/macro.h>
33 #include <pulsecore/core-util.h>
34
35 #include "timeval.h"
36
pa_gettimeofday(struct timeval * tv)37 struct timeval *pa_gettimeofday(struct timeval *tv) {
38 pa_assert(tv);
39
40 #if defined(OS_IS_WIN32)
41 /*
42 * Copied from implementation by Steven Edwards (LGPL).
43 * Found on wine mailing list.
44 */
45 #if defined(_MSC_VER) || defined(__BORLANDC__)
46 #define EPOCHFILETIME (116444736000000000i64)
47 #else
48 #define EPOCHFILETIME (116444736000000000LL)
49 #endif
50 {
51 FILETIME ft;
52 LARGE_INTEGER li;
53 int64_t t;
54
55 GetSystemTimeAsFileTime(&ft);
56 li.LowPart = ft.dwLowDateTime;
57 li.HighPart = ft.dwHighDateTime;
58 t = li.QuadPart; /* In 100-nanosecond intervals */
59 t -= EPOCHFILETIME; /* Offset to the Epoch time */
60 t /= 10; /* In microseconds */
61 tv->tv_sec = (time_t) (t / PA_USEC_PER_SEC);
62 tv->tv_usec = (suseconds_t) (t % PA_USEC_PER_SEC);
63 }
64 #elif defined(HAVE_GETTIMEOFDAY)
65 pa_assert_se(gettimeofday(tv, NULL) == 0);
66 #else
67 #error "Platform lacks gettimeofday() or equivalent function."
68 #endif
69
70 return tv;
71 }
72
pa_timeval_diff(const struct timeval * a,const struct timeval * b)73 pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) {
74 pa_usec_t r;
75
76 pa_assert(a);
77 pa_assert(b);
78
79 /* Check which is the earlier time and swap the two arguments if required. */
80 if (PA_UNLIKELY(pa_timeval_cmp(a, b) < 0)) {
81 const struct timeval *c;
82 c = a;
83 a = b;
84 b = c;
85 }
86
87 /* Calculate the second difference*/
88 r = ((pa_usec_t) a->tv_sec - (pa_usec_t) b->tv_sec) * PA_USEC_PER_SEC;
89
90 /* Calculate the microsecond difference */
91 if (a->tv_usec > b->tv_usec)
92 r += (pa_usec_t) a->tv_usec - (pa_usec_t) b->tv_usec;
93 else if (a->tv_usec < b->tv_usec)
94 r -= (pa_usec_t) b->tv_usec - (pa_usec_t) a->tv_usec;
95
96 return r;
97 }
98
pa_timeval_cmp(const struct timeval * a,const struct timeval * b)99 int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) {
100 pa_assert(a);
101 pa_assert(b);
102
103 if (a->tv_sec < b->tv_sec)
104 return -1;
105
106 if (a->tv_sec > b->tv_sec)
107 return 1;
108
109 if (a->tv_usec < b->tv_usec)
110 return -1;
111
112 if (a->tv_usec > b->tv_usec)
113 return 1;
114
115 return 0;
116 }
117
pa_timeval_age(const struct timeval * tv)118 pa_usec_t pa_timeval_age(const struct timeval *tv) {
119 struct timeval now;
120 pa_assert(tv);
121
122 return pa_timeval_diff(pa_gettimeofday(&now), tv);
123 }
124
pa_timeval_add(struct timeval * tv,pa_usec_t v)125 struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v) {
126 time_t secs;
127 pa_assert(tv);
128
129 secs = (time_t) (v/PA_USEC_PER_SEC);
130
131 if (PA_UNLIKELY(tv->tv_sec > PA_INT_TYPE_MAX(time_t) - secs))
132 goto overflow;
133
134 tv->tv_sec += secs;
135 v -= (pa_usec_t) secs * PA_USEC_PER_SEC;
136 tv->tv_usec += (suseconds_t) v;
137
138 /* Normalize */
139 while ((pa_usec_t) tv->tv_usec >= PA_USEC_PER_SEC) {
140
141 if (PA_UNLIKELY(tv->tv_sec >= PA_INT_TYPE_MAX(time_t)))
142 goto overflow;
143
144 tv->tv_sec++;
145 tv->tv_usec -= (suseconds_t) PA_USEC_PER_SEC;
146 }
147
148 return tv;
149
150 overflow:
151 tv->tv_sec = PA_INT_TYPE_MAX(time_t);
152 tv->tv_usec = (suseconds_t) (PA_USEC_PER_SEC-1);
153 return tv;
154 }
155
pa_timeval_sub(struct timeval * tv,pa_usec_t v)156 struct timeval* pa_timeval_sub(struct timeval *tv, pa_usec_t v) {
157 time_t secs;
158 pa_assert(tv);
159
160 secs = (time_t) (v/PA_USEC_PER_SEC);
161
162 if (PA_UNLIKELY(tv->tv_sec < secs))
163 goto underflow;
164
165 tv->tv_sec -= secs;
166 v -= (pa_usec_t) secs * PA_USEC_PER_SEC;
167
168 if (tv->tv_usec >= (suseconds_t) v)
169 tv->tv_usec -= (suseconds_t) v;
170 else {
171
172 if (PA_UNLIKELY(tv->tv_sec <= 0))
173 goto underflow;
174
175 tv->tv_sec --;
176 tv->tv_usec += (suseconds_t) (PA_USEC_PER_SEC - v);
177 }
178
179 return tv;
180
181 underflow:
182 tv->tv_sec = 0;
183 tv->tv_usec = 0;
184 return tv;
185 }
186
pa_timeval_store(struct timeval * tv,pa_usec_t v)187 struct timeval* pa_timeval_store(struct timeval *tv, pa_usec_t v) {
188 pa_assert(tv);
189
190 if (PA_UNLIKELY(v == PA_USEC_INVALID)) {
191 tv->tv_sec = PA_INT_TYPE_MAX(time_t);
192 tv->tv_usec = (suseconds_t) (PA_USEC_PER_SEC-1);
193
194 return tv;
195 }
196
197 tv->tv_sec = (time_t) (v / PA_USEC_PER_SEC);
198 tv->tv_usec = (suseconds_t) (v % PA_USEC_PER_SEC);
199
200 return tv;
201 }
202
pa_timeval_load(const struct timeval * tv)203 pa_usec_t pa_timeval_load(const struct timeval *tv) {
204
205 if (PA_UNLIKELY(!tv))
206 return PA_USEC_INVALID;
207
208 return
209 (pa_usec_t) tv->tv_sec * PA_USEC_PER_SEC +
210 (pa_usec_t) tv->tv_usec;
211 }
212