timeval: add UNLIKELY annotation
[platform/upstream/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/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     tv->tv_sec = (time_t) (v / PA_USEC_PER_SEC);
197     tv->tv_usec = (suseconds_t) (v % PA_USEC_PER_SEC);
198
199     return tv;
200 }
201
202 pa_usec_t pa_timeval_load(const struct timeval *tv) {
203     pa_assert(tv);
204
205     return
206         (pa_usec_t) tv->tv_sec * PA_USEC_PER_SEC +
207         (pa_usec_t) tv->tv_usec;
208 }