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