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