• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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