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