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