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