34e3de9523cb91a6c4142cf36ec6d540d21d7fe6
[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 div 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 div, const struct timeval *tv,
114 struct timeval *result)
115 {
116 long unsigned q = tv->tv_usec / div;
117 result->tv_sec = tv->tv_sec / div;
118 result->tv_usec = (tv->tv_sec - result->tv_sec * div) * 1000 * 1000 / div;
119 if (result->tv_usec + q >= 1000 * 1000) {
120 result->tv_sec++;
121 result->tv_usec = 1000 * 1000 - result->tv_usec - q;
122 } else
123 result->tv_usec += q;
124 }
125
126 /**
127 * compute a convex combination of two time values
128 *
129 * \param a the first coefiicent
130 * \param tv1 the first time value
131 * \param b the second coefiicent
132 * \param tv2 the second time value
133 * \param result holds the convex combination upon return
134 *
135 * compute x := (a * tv1 + b * tv2) / (|a| + |b|). a, b may be negative.
136 * returns sign(x) and stores |x| in the result pointer.
137 */
138 int tv_convex_combination(const long a, const struct timeval *tv1,
139 const long b, const struct timeval *tv2,
140 struct timeval *result)
141 {
142 struct timeval tmp1, tmp2, tmp3;
143 int ret = 1, subtract = ((a > 0 && b < 0) || (a < 0 && b > 0));
144 unsigned long a1 = PARA_ABS(a), b1 = PARA_ABS(b);
145
146 tv_scale(a1, tv1, &tmp1);
147 tv_scale(b1, tv2, &tmp2);
148 if (subtract)
149 ret = tv_diff(&tmp1, &tmp2, &tmp3);
150 else
151 tv_add(&tmp1, &tmp2, &tmp3);
152 if (a1 + b1)
153 tv_divide(a1 + b1, &tmp3, result);
154 else {
155 result->tv_sec = 0;
156 result->tv_usec = 0;
157 }
158 if (!a || !b) {
159 if (a + b < 0)
160 ret = -1;
161 } else
162 if (a < 0)
163 ret = -ret;
164 return ret;
165 }