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