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