Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / lwp / timer.c
CommitLineData
805e021f
CE
1/*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10/*******************************************************************\
11* *
12* *
13* Information Technology Center *
14* Carnegie-Mellon University *
15* *
16* *
17* *
18\*******************************************************************/
19
20
21#include <afsconfig.h>
22#include <afs/param.h>
23
24#include <roken.h>
25
26#define _TIMER_IMPL_
27#include "timer.h"
28#include "lwp.h"
29
30
31
32
33typedef unsigned char bool;
34#define FALSE 0
35#define TRUE 1
36
37
38#define expiration TotalTime
39
40#define new_elem() (malloc(sizeof(struct TM_Elem)))
41
42#define MILLION 1000000
43
44static int globalInitDone = 0;
45
46/* t1 = t2 - t3 */
47static void
48subtract(struct timeval *t1, struct timeval *t2,
49 struct timeval *t3)
50{
51 int sec2, usec2, sec3, usec3;
52
53 sec2 = t2->tv_sec;
54 usec2 = t2->tv_usec;
55 sec3 = t3->tv_sec;
56 usec3 = t3->tv_usec;
57
58 /* Take care of the probably non-existent case where the
59 * usec field has more than 1 second in it. */
60
61 while (usec3 > usec2) {
62 usec2 += MILLION;
63 sec2--;
64 }
65
66 /* Check for a negative time and use zero for the answer,
67 * since the tv_sec field is unsigned */
68
69 if (sec3 > sec2) {
70 t1->tv_usec = 0;
71 t1->tv_sec = (afs_uint32) 0;
72 } else {
73 t1->tv_usec = usec2 - usec3;
74 t1->tv_sec = sec2 - sec3;
75 }
76}
77
78/* t1 += t2; */
79
80static void
81add(struct timeval *t1, struct timeval *t2)
82{
83 t1->tv_usec += t2->tv_usec;
84 t1->tv_sec += t2->tv_sec;
85 if (t1->tv_usec >= MILLION) {
86 t1->tv_sec++;
87 t1->tv_usec -= MILLION;
88 }
89}
90
91/* t1 == t2 */
92
93int
94TM_eql(struct timeval *t1, struct timeval *t2)
95{
96 return (t1->tv_usec == t2->tv_usec) && (t1->tv_sec == t2->tv_sec);
97}
98
99/* t1 >= t2 */
100
101/*
102obsolete, commentless procedure, all done by hand expansion now.
103static bool geq(struct timeval *t1, struct timeval *t2)
104{
105 return (t1->tv_sec > t2->tv_sec) ||
106 (t1->tv_sec == t2->tv_sec && t1->tv_usec >= t2->tv_usec);
107}
108*/
109
110static bool
111blocking(struct TM_Elem *t)
112{
113 return (t->TotalTime.tv_sec < 0 || t->TotalTime.tv_usec < 0);
114}
115
116
117
118/*
119 Initializes a list -- returns -1 if failure, else 0.
120*/
121
122int
123TM_Init(struct TM_Elem **list)
124{
125 if (!globalInitDone) {
126 FT_Init(0, 0);
127 globalInitDone = 1;
128 }
129 *list = new_elem();
130 if (*list == NULL)
131 return -1;
132 else {
133 (*list)->Next = *list;
134 (*list)->Prev = *list;
135 (*list)->TotalTime.tv_sec = 0;
136 (*list)->TotalTime.tv_usec = 0;
137 (*list)->TimeLeft.tv_sec = 0;
138 (*list)->TimeLeft.tv_usec = 0;
139 (*list)->BackPointer = NULL;
140
141 return 0;
142 }
143}
144
145int
146TM_Final(struct TM_Elem **list)
147{
148 if (list == NULL || *list == NULL)
149 return -1;
150 else {
151 free(*list);
152 *list = NULL;
153 return 0;
154 }
155}
156
157/*
158 Inserts elem into the timer list pointed to by *tlistPtr.
159*/
160
161void
162TM_Insert(struct TM_Elem *tlistPtr, struct TM_Elem *elem)
163{
164 struct TM_Elem *next;
165
166 /* TimeLeft must be set for function IOMGR with infinite timeouts */
167 elem->TimeLeft = elem->TotalTime;
168
169 /* Special case -- infinite timeout */
170 if (blocking(elem)) {
171 openafs_insque(elem, tlistPtr->Prev);
172 return;
173 }
174
175 /* Finite timeout, set expiration time */
176 FT_AGetTimeOfDay(&elem->expiration, 0);
177 add(&elem->expiration, &elem->TimeLeft);
178 next = NULL;
179 FOR_ALL_ELTS(p, tlistPtr, {
180 if (blocking(p)
181 || !(elem->TimeLeft.tv_sec > p->TimeLeft.tv_sec
182 || (elem->TimeLeft.tv_sec == p->TimeLeft.tv_sec
183 && elem->TimeLeft.tv_usec >=
184 p->TimeLeft.tv_usec))
185 ) {
186 next = p; /* Save ptr to element that will be after this one */
187 break;}
188 }
189 )
190
191 if (next == NULL)
192 next = tlistPtr;
193 openafs_insque(elem, next->Prev);
194}
195
196/*
197 Walks through the specified list and updates the TimeLeft fields in it.
198 Returns number of expired elements in the list.
199*/
200
201int
202TM_Rescan(struct TM_Elem *tlist) /* head pointer of timer list */
203{
204 struct timeval time;
205 int expired;
206
207 FT_AGetTimeOfDay(&time, 0);
208 expired = 0;
209 FOR_ALL_ELTS(e, tlist, {
210 if (!blocking(e)) {
211 subtract(&e->TimeLeft, &e->expiration, &time);
212 if (0 > e->TimeLeft.tv_sec
213 || (0 == e->TimeLeft.tv_sec && 0 >= e->TimeLeft.tv_usec))
214 expired++;}
215 }
216 )
217 return expired;
218}
219
220/*
221 RETURNS POINTER TO earliest expired entry from tlist.
222 Returns 0 if no expired entries are present.
223*/
224
225struct TM_Elem *
226TM_GetExpired(struct TM_Elem *tlist) /* head pointer of timer list */
227{
228 FOR_ALL_ELTS(e, tlist, {
229 if (!blocking(e)
230 && (0 > e->TimeLeft.tv_sec
231 || (0 == e->TimeLeft.tv_sec
232 && 0 >= e->TimeLeft.tv_usec)))
233 return e;}
234 )
235 return NULL;
236}
237
238/*
239 Returns a pointer to the earliest unexpired element in tlist.
240 Its TimeLeft field will specify how much time is left.
241 Returns 0 if tlist is empty or if there are no unexpired elements.
242*/
243
244struct TM_Elem *
245TM_GetEarliest(struct TM_Elem *tlist)
246{
247 struct TM_Elem *e;
248
249 e = tlist->Next;
250 return (e == tlist ? NULL : e);
251}
252
253/* This used to be in hputils.c, but it's only use is in the LWP package. */
254/*
255 * Emulate the vax instructions for queue insertion and deletion, somewhat.
256 * A std_queue structure is defined here and used by these routines. These
257 * routines use caddr_ts so they can operate on any structure. The std_queue
258 * structure is used rather than proc structures so that when the proc struct
259 * changes only process management code breaks. The ideal solution would be
260 * to define a std_queue as a global type which is part of all the structures
261 * which are manipulated by these routines. This would involve considerable
262 * effort...
263 */
264
265void
266openafs_insque(struct TM_Elem *elementp, struct TM_Elem *quep)
267{
268 elementp->Next = quep->Next;
269 elementp->Prev = quep;
270
271 quep->Next->Prev = elementp;
272 quep->Next = elementp;
273}
274
275void
276openafs_remque(struct TM_Elem *elementp)
277{
278 elementp->Next->Prev = elementp->Prev;
279 elementp->Prev->Next = elementp->Next;
280 elementp->Prev = elementp->Next = NULL;
281}