]> code.delx.au - pulseaudio/blob - src/pulse/timeval.c
Merge branch 'master' into dbus-work
[pulseaudio] / src / pulse / timeval.c
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, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stddef.h>
28 #include <sys/time.h>
29
30 #ifdef HAVE_WINDOWS_H
31 #include <windows.h>
32 #endif
33
34 #include <pulsecore/winsock.h>
35 #include <pulsecore/macro.h>
36 #include <pulsecore/core-util.h>
37
38 #include "timeval.h"
39
40 struct timeval *pa_gettimeofday(struct timeval *tv) {
41 #ifdef HAVE_GETTIMEOFDAY
42 pa_assert(tv);
43
44 pa_assert_se(gettimeofday(tv, NULL) == 0);
45 return tv;
46 #elif defined(OS_IS_WIN32)
47 /*
48 * Copied from implementation by Steven Edwards (LGPL).
49 * Found on wine mailing list.
50 */
51
52 #if defined(_MSC_VER) || defined(__BORLANDC__)
53 #define EPOCHFILETIME (116444736000000000i64)
54 #else
55 #define EPOCHFILETIME (116444736000000000LL)
56 #endif
57
58 FILETIME ft;
59 LARGE_INTEGER li;
60 int64_t t;
61
62 pa_assert(tv);
63
64 GetSystemTimeAsFileTime(&ft);
65 li.LowPart = ft.dwLowDateTime;
66 li.HighPart = ft.dwHighDateTime;
67 t = li.QuadPart; /* In 100-nanosecond intervals */
68 t -= EPOCHFILETIME; /* Offset to the Epoch time */
69 t /= 10; /* In microseconds */
70 tv->tv_sec = (time_t) (t / PA_USEC_PER_SEC);
71 tv->tv_usec = (suseconds_t) (t % PA_USEC_PER_SEC);
72
73 return tv;
74 #else
75 #error "Platform lacks gettimeofday() or equivalent function."
76 #endif
77 }
78
79 pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) {
80 pa_usec_t r;
81
82 pa_assert(a);
83 pa_assert(b);
84
85 /* Check which whan is the earlier time and swap the two arguments if required. */
86 if (PA_UNLIKELY(pa_timeval_cmp(a, b) < 0)) {
87 const struct timeval *c;
88 c = a;
89 a = b;
90 b = c;
91 }
92
93 /* Calculate the second difference*/
94 r = ((pa_usec_t) a->tv_sec - (pa_usec_t) b->tv_sec) * PA_USEC_PER_SEC;
95
96 /* Calculate the microsecond difference */
97 if (a->tv_usec > b->tv_usec)
98 r += (pa_usec_t) a->tv_usec - (pa_usec_t) b->tv_usec;
99 else if (a->tv_usec < b->tv_usec)
100 r -= (pa_usec_t) b->tv_usec - (pa_usec_t) a->tv_usec;
101
102 return r;
103 }
104
105 int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) {
106 pa_assert(a);
107 pa_assert(b);
108
109 if (a->tv_sec < b->tv_sec)
110 return -1;
111
112 if (a->tv_sec > b->tv_sec)
113 return 1;
114
115 if (a->tv_usec < b->tv_usec)
116 return -1;
117
118 if (a->tv_usec > b->tv_usec)
119 return 1;
120
121 return 0;
122 }
123
124 pa_usec_t pa_timeval_age(const struct timeval *tv) {
125 struct timeval now;
126 pa_assert(tv);
127
128 return pa_timeval_diff(pa_gettimeofday(&now), tv);
129 }
130
131 struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v) {
132 time_t secs;
133 pa_assert(tv);
134
135 secs = (time_t) (v/PA_USEC_PER_SEC);
136
137 if (PA_UNLIKELY(tv->tv_sec > PA_INT_TYPE_MAX(time_t) - secs))
138 goto overflow;
139
140 tv->tv_sec += secs;
141 v -= (pa_usec_t) secs * PA_USEC_PER_SEC;
142 tv->tv_usec += (suseconds_t) v;
143
144 /* Normalize */
145 while ((pa_usec_t) tv->tv_usec >= PA_USEC_PER_SEC) {
146
147 if (PA_UNLIKELY(tv->tv_sec >= PA_INT_TYPE_MAX(time_t)))
148 goto overflow;
149
150 tv->tv_sec++;
151 tv->tv_usec -= (suseconds_t) PA_USEC_PER_SEC;
152 }
153
154 return tv;
155
156 overflow:
157 tv->tv_sec = PA_INT_TYPE_MAX(time_t);
158 tv->tv_usec = (suseconds_t) (PA_USEC_PER_SEC-1);
159 return tv;
160 }
161
162 struct timeval* pa_timeval_sub(struct timeval *tv, pa_usec_t v) {
163 time_t secs;
164 pa_assert(tv);
165
166 secs = (time_t) (v/PA_USEC_PER_SEC);
167
168 if (PA_UNLIKELY(tv->tv_sec < secs))
169 goto underflow;
170
171 tv->tv_sec -= secs;
172 v -= (pa_usec_t) secs * PA_USEC_PER_SEC;
173
174 if (tv->tv_usec >= (suseconds_t) v)
175 tv->tv_usec -= (suseconds_t) v;
176 else {
177
178 if (PA_UNLIKELY(tv->tv_sec <= 0))
179 goto underflow;
180
181 tv->tv_sec --;
182 tv->tv_usec += (suseconds_t) (PA_USEC_PER_SEC - v);
183 }
184
185 return tv;
186
187 underflow:
188 tv->tv_sec = 0;
189 tv->tv_usec = 0;
190 return tv;
191 }
192
193 struct timeval* pa_timeval_store(struct timeval *tv, pa_usec_t v) {
194 pa_assert(tv);
195
196 if (PA_UNLIKELY(v == PA_USEC_INVALID)) {
197 tv->tv_sec = PA_INT_TYPE_MAX(time_t);
198 tv->tv_usec = (suseconds_t) (PA_USEC_PER_SEC-1);
199
200 return tv;
201 }
202
203 tv->tv_sec = (time_t) (v / PA_USEC_PER_SEC);
204 tv->tv_usec = (suseconds_t) (v % PA_USEC_PER_SEC);
205
206 return tv;
207 }
208
209 pa_usec_t pa_timeval_load(const struct timeval *tv) {
210
211 if (PA_UNLIKELY(!tv))
212 return PA_USEC_INVALID;
213
214 return
215 (pa_usec_t) tv->tv_sec * PA_USEC_PER_SEC +
216 (pa_usec_t) tv->tv_usec;
217 }