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