Commit | Line | Data |
---|---|---|
e1a31032 | 1 | /* |
e1a31032 KM |
2 | * Copyright (c) 1989 Jan-Simon Pendry |
3 | * Copyright (c) 1989 Imperial College of Science, Technology & Medicine | |
4 | * Copyright (c) 1989 The Regents of the University of California. | |
5 | * All rights reserved. | |
6 | * | |
7 | * This code is derived from software contributed to Berkeley by | |
8 | * Jan-Simon Pendry at Imperial College, London. | |
9 | * | |
af359dea C |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. All advertising materials mentioning features or use of this software | |
19 | * must display the following acknowledgement: | |
20 | * This product includes software developed by the University of | |
21 | * California, Berkeley and its contributors. | |
22 | * 4. Neither the name of the University nor the names of its contributors | |
23 | * may be used to endorse or promote products derived from this software | |
24 | * without specific prior written permission. | |
25 | * | |
26 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
27 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
30 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
31 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
32 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
34 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
35 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
36 | * SUCH DAMAGE. | |
37 | * | |
38 | * @(#)clock.c 5.3 (Berkeley) 5/12/91 | |
39 | * | |
40 | * $Id: clock.c,v 5.2.1.5 91/05/07 22:17:49 jsp Alpha $ | |
e1a31032 | 41 | * |
e1a31032 KM |
42 | */ |
43 | ||
44 | /* | |
45 | * Callouts. | |
46 | * | |
47 | * Modelled on kernel object of the same name. | |
48 | * See usual references. | |
49 | * | |
50 | * Use of a heap-based mechanism was rejected: | |
2664d859 JSP |
51 | * 1. more complex implementation needed. |
52 | * 2. not obvious that a list is too slow for Amd. | |
e1a31032 KM |
53 | */ |
54 | ||
55 | #include "am.h" | |
56 | ||
57 | typedef struct callout callout; | |
58 | struct callout { | |
59 | callout *c_next; /* List of callouts */ | |
60 | void (*c_fn)(); /* Function to call */ | |
61 | voidp c_closure; /* Closure to pass to call */ | |
62 | time_t c_time; /* Time of call */ | |
63 | int c_id; /* Unique identifier */ | |
64 | }; | |
65 | ||
66 | static callout callouts; /* List of pending callouts */ | |
67 | static callout *free_callouts; /* Cache of free callouts */ | |
68 | static int nfree_callouts; /* Number on free list */ | |
69 | static int callout_id; /* Next free callout identifier */ | |
70 | time_t next_softclock; /* Time of next call to softclock() */ | |
71 | ||
72 | /* | |
73 | * Number of callout slots we keep on the free list | |
74 | */ | |
75 | #define CALLOUT_FREE_SLOP 10 | |
76 | ||
77 | /* | |
2664d859 | 78 | * Global assumption: valid id's are non-zero. |
e1a31032 KM |
79 | */ |
80 | #define CID_ALLOC() (++callout_id) | |
81 | #define CID_UNDEF (0) | |
82 | ||
2664d859 | 83 | static callout *alloc_callout(P_void); |
e1a31032 KM |
84 | static callout *alloc_callout() |
85 | { | |
86 | callout *cp = free_callouts; | |
87 | if (cp) { | |
88 | --nfree_callouts; | |
89 | free_callouts = free_callouts->c_next; | |
90 | return cp; | |
91 | } | |
92 | return ALLOC(callout); | |
93 | } | |
94 | ||
2664d859 | 95 | static void free_callout P((callout *cp)); |
e1a31032 KM |
96 | static void free_callout(cp) |
97 | callout *cp; | |
98 | { | |
99 | if (nfree_callouts > CALLOUT_FREE_SLOP) { | |
100 | free((voidp) cp); | |
101 | } else { | |
102 | cp->c_next = free_callouts; | |
103 | free_callouts = cp; | |
104 | nfree_callouts++; | |
105 | } | |
106 | } | |
107 | ||
108 | /* | |
109 | * Schedule a callout. | |
110 | * | |
111 | * (*fn)(closure) will be called at clocktime() + secs | |
112 | */ | |
2664d859 | 113 | int timeout P((unsigned int secs, void (*fn)(), voidp closure)); |
e1a31032 KM |
114 | int timeout(secs, fn, closure) |
115 | unsigned int secs; | |
116 | void (*fn)(); | |
117 | voidp closure; | |
118 | { | |
119 | callout *cp, *cp2; | |
120 | time_t t = clocktime() + secs; | |
121 | ||
122 | /* | |
123 | * Allocate and fill in a new callout structure | |
124 | */ | |
125 | callout *cpnew = alloc_callout(); | |
126 | cpnew->c_closure = closure; | |
127 | cpnew->c_fn = fn; | |
128 | cpnew->c_time = t; | |
129 | cpnew->c_id = CID_ALLOC(); | |
130 | ||
131 | if (t < next_softclock) | |
132 | next_softclock = t; | |
133 | ||
134 | /* | |
135 | * Find the correct place in the list | |
136 | */ | |
137 | for (cp = &callouts; cp2 = cp->c_next; cp = cp2) | |
138 | if (cp2->c_time >= t) | |
139 | break; | |
140 | ||
141 | /* | |
142 | * And link it in | |
143 | */ | |
144 | cp->c_next = cpnew; | |
145 | cpnew->c_next = cp2; | |
146 | ||
147 | /* | |
148 | * Return callout identifier | |
149 | */ | |
150 | return cpnew->c_id; | |
151 | } | |
152 | ||
153 | /* | |
154 | * De-schedule a callout | |
155 | */ | |
2664d859 | 156 | void untimeout P((int id)); |
e1a31032 KM |
157 | void untimeout(id) |
158 | int id; | |
159 | { | |
160 | callout *cp, *cp2; | |
161 | for (cp = &callouts; cp2 = cp->c_next; cp = cp2) { | |
162 | if (cp2->c_id == id) { | |
163 | cp->c_next = cp2->c_next; | |
164 | free_callout(cp2); | |
165 | break; | |
166 | } | |
167 | } | |
168 | } | |
169 | ||
2664d859 JSP |
170 | /* |
171 | * Reschedule after clock changed | |
172 | */ | |
173 | void reschedule_timeouts P((time_t now, time_t then)); | |
174 | void reschedule_timeouts(now, then) | |
175 | time_t now; | |
176 | time_t then; | |
177 | { | |
178 | callout *cp; | |
179 | ||
180 | for (cp = callouts.c_next; cp; cp = cp->c_next) { | |
181 | if (cp->c_time >= now && cp->c_time <= then) { | |
182 | plog(XLOG_WARNING, "job %d rescheduled to run immediately", cp->c_id); | |
183 | #ifdef DEBUG | |
184 | dlog("rescheduling job %d back %d seconds", | |
185 | cp->c_id, cp->c_time - now); | |
186 | #endif | |
187 | next_softclock = cp->c_time = now; | |
188 | } | |
189 | } | |
190 | } | |
191 | ||
e1a31032 KM |
192 | /* |
193 | * Clock handler | |
194 | */ | |
2664d859 | 195 | int softclock(P_void); |
e1a31032 KM |
196 | int softclock() |
197 | { | |
198 | time_t now; | |
199 | callout *cp; | |
200 | ||
201 | do { | |
202 | if (task_notify_todo) | |
2664d859 | 203 | do_task_notify(); |
e1a31032 KM |
204 | |
205 | now = clocktime(); | |
206 | ||
207 | /* | |
208 | * While there are more callouts waiting... | |
209 | */ | |
210 | while ((cp = callouts.c_next) && cp->c_time <= now) { | |
211 | /* | |
212 | * Extract first from list, save fn & closure and | |
213 | * unlink callout from list and free. | |
214 | * Finally call function. | |
215 | * | |
216 | * The free is done first because | |
217 | * it is quite common that the | |
218 | * function will call timeout() | |
219 | * and try to allocate a callout | |
220 | */ | |
221 | void (*fn)() = cp->c_fn; | |
222 | voidp closure = cp->c_closure; | |
223 | ||
224 | callouts.c_next = cp->c_next; | |
225 | free_callout(cp); | |
226 | #ifdef DEBUG | |
227 | /*dlog("Calling %#x(%#x)", fn, closure);*/ | |
228 | #endif /* DEBUG */ | |
229 | (*fn)(closure); | |
230 | } | |
231 | ||
232 | } while (task_notify_todo); | |
233 | ||
234 | /* | |
235 | * Return number of seconds to next event, | |
236 | * or 0 if there is no event. | |
237 | */ | |
238 | if (cp = callouts.c_next) | |
239 | return cp->c_time - now; | |
240 | return 0; | |
241 | } |