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