Fix core dump on audiod pipe errors
[paraslash.git] / time.c
1 #include "para.h"
2 /** \file time.c helper functions for dealing with timeouts */
3
4 /**
5  * convert struct timeval to milliseconds
6  *
7  * \param tv the value to convert
8  *
9  * \return The number off milliseconds in \a tv
10  */
11 long unsigned tv2ms(const struct timeval *tv)
12 {
13         return tv->tv_sec * 1000 + (tv->tv_usec + 500)/ 1000;
14 }
15
16 /**
17  * convert milliseconds to struct timeval
18  *
19  * \param n the number of milliseconds
20  * \param tv will be filled in by the function
21  */
22 void ms2tv(long unsigned n, struct timeval *tv)
23 {
24         tv->tv_sec = n / 1000;
25         tv->tv_usec = (n % 1000) * 1000;
26 }
27
28 /**
29  * convert double to struct timeval
30  *
31  * \param x the value to convert
32  * \param tv converted value is stored here
33  */
34 void d2tv(double x, struct timeval *tv)
35 {
36         tv->tv_sec = x;
37         tv->tv_usec = (x - (double)tv->tv_sec) * 1000.0 * 1000.0 + 0.5;
38 }
39
40 /**
41  * compute the difference of two time values
42  *
43  * \param b minuend
44  * \param a subtrahend
45  * \param diff difference is stored here
46  *
47  * \return If b > a, compute b - a and return 1. if b < a
48  * compute a - b and return -1. If \a diff is not  \p NULL, \a diff gets
49  * filled in with the absolute value |b - a|.
50  */
51 int tv_diff(const struct timeval *b, const struct timeval *a, struct timeval *diff)
52 {
53         int ret = 1;
54
55         if ((b->tv_sec < a->tv_sec) ||
56                 ((b->tv_sec == a->tv_sec) && (b->tv_usec < a->tv_usec))) {
57                 const struct timeval *tmp = a;
58                 a = b;
59                 b = tmp;
60                 ret = -1;
61         }
62         if (!diff)
63                 return ret;
64         diff->tv_sec = b->tv_sec - a->tv_sec;
65         if (b->tv_usec < a->tv_usec) {
66                 diff->tv_sec--;
67                 diff->tv_usec = 1000 * 1000 - a->tv_usec + b->tv_usec;
68         } else
69                 diff->tv_usec = b->tv_usec - a->tv_usec;
70         return ret;
71 }
72
73 /**
74  * add two structs of type timeval
75  *
76  * \param a first addend
77  * \param b second addend
78  * \param sum holds the sum upon return
79  */
80 void tv_add(const struct timeval *a, const struct timeval *b,
81         struct timeval *sum)
82 {
83         sum->tv_sec = a->tv_sec + b->tv_sec;
84         if (a->tv_usec + b->tv_usec >= 1000 * 1000) {
85                 sum->tv_sec++;
86                 sum->tv_usec = a->tv_usec + b->tv_usec - 1000 * 1000;
87         } else
88                 sum->tv_usec = a->tv_usec + b->tv_usec;
89 }
90
91 /**
92  * compute integer multiple of given struct timeval
93  *
94  * \param mult the integer value to multiply with
95  * \param tv the timevalue to multiply
96  * \param result holds mult * tv upon return
97  */
98 void tv_scale(const unsigned long mult, const struct timeval *tv,
99         struct timeval *result)
100 {
101         result->tv_sec = mult * tv->tv_sec;
102         result->tv_sec += tv->tv_usec * mult / 1000 / 1000;
103         result->tv_usec = tv->tv_usec * mult % (1000 * 1000);
104 }
105
106 /**
107  * compute fraction of given struct timeval
108  *
109  * \param divisor the integer value to divide by
110  * \param tv the timevalue to divide
111  * \param result holds (1 / mult) * tv upon return
112  */
113 void tv_divide(const unsigned long divisor, const struct timeval *tv,
114         struct timeval *result)
115 {
116         long unsigned q = tv->tv_usec / divisor;
117         result->tv_sec = tv->tv_sec / divisor;
118         result->tv_usec = (tv->tv_sec - result->tv_sec * divisor)
119                 * 1000 * 1000 / divisor;
120         if (result->tv_usec + q >= 1000 * 1000) {
121                 result->tv_sec++;
122                 result->tv_usec = 1000 * 1000 - result->tv_usec - q;
123         } else
124                 result->tv_usec += q;
125 }
126
127 /**
128  * compute a convex combination of two time values
129  *
130  * \param a the first coefiicent
131  * \param tv1 the first time value
132  * \param b the second coefiicent
133  * \param tv2 the second time value
134  * \param result holds the convex combination upon return
135  *
136  * compute x := (a * tv1 + b * tv2) / (|a| + |b|). a, b may be negative.
137  * returns sign(x) and stores |x| in the result pointer.
138  */
139 int tv_convex_combination(const long a, const struct timeval *tv1,
140                 const long b, const struct timeval *tv2,
141                 struct timeval *result)
142 {
143         struct timeval tmp1, tmp2, tmp3;
144         int ret = 1, subtract = ((a > 0 && b < 0) || (a < 0 && b > 0));
145         unsigned long a1 = PARA_ABS(a), b1 = PARA_ABS(b);
146
147         tv_scale(a1, tv1, &tmp1);
148         tv_scale(b1, tv2, &tmp2);
149         if (subtract)
150                 ret = tv_diff(&tmp1, &tmp2, &tmp3);
151         else
152                 tv_add(&tmp1, &tmp2, &tmp3);
153         if (a1 + b1)
154                 tv_divide(a1 + b1, &tmp3, result);
155         else {
156                 result->tv_sec = 0;
157                 result->tv_usec = 0;
158         }
159         if (!a || !b) {
160                 if (a + b < 0)
161                         ret = -1;
162         } else
163                 if (a < 0)
164                         ret = -ret;
165         return ret;
166 }