clock.c revision 38494
1130803Smarcel/* 2130803Smarcel * Copyright (c) 1997-1998 Erez Zadok 3130803Smarcel * Copyright (c) 1989 Jan-Simon Pendry 4130803Smarcel * Copyright (c) 1989 Imperial College of Science, Technology & Medicine 5130803Smarcel * Copyright (c) 1989 The Regents of the University of California. 6130803Smarcel * All rights reserved. 7130803Smarcel * 8130803Smarcel * This code is derived from software contributed to Berkeley by 9130803Smarcel * Jan-Simon Pendry at Imperial College, London. 10130803Smarcel * 11130803Smarcel * Redistribution and use in source and binary forms, with or without 12130803Smarcel * modification, are permitted provided that the following conditions 13130803Smarcel * are met: 14130803Smarcel * 1. Redistributions of source code must retain the above copyright 15130803Smarcel * notice, this list of conditions and the following disclaimer. 16130803Smarcel * 2. Redistributions in binary form must reproduce the above copyright 17130803Smarcel * notice, this list of conditions and the following disclaimer in the 18130803Smarcel * documentation and/or other materials provided with the distribution. 19130803Smarcel * 3. All advertising materials mentioning features or use of this software 20130803Smarcel * must display the following acknowledgement: 21130803Smarcel * This product includes software developed by the University of 22130803Smarcel * California, Berkeley and its contributors. 23130803Smarcel * 4. Neither the name of the University nor the names of its contributors 24130803Smarcel * may be used to endorse or promote products derived from this software 25130803Smarcel * without specific prior written permission. 26130803Smarcel * 27130803Smarcel * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28130803Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29130803Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30130803Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31130803Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32130803Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33130803Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34130803Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35130803Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36130803Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37130803Smarcel * SUCH DAMAGE. 38130803Smarcel * 39130803Smarcel * %W% (Berkeley) %G% 40130803Smarcel * 41130803Smarcel * $Id: clock.c,v 5.2.2.1 1992/02/09 15:08:20 jsp beta $ 42130803Smarcel * 43130803Smarcel */ 44130803Smarcel 45130803Smarcel/* 46130803Smarcel * Callouts. 47130803Smarcel * 48130803Smarcel * Modelled on kernel object of the same name. 49130803Smarcel * See usual references. 50130803Smarcel * 51130803Smarcel * Use of a heap-based mechanism was rejected: 52130803Smarcel * 1. more complex implementation needed. 53130803Smarcel * 2. not obvious that a list is too slow for Amd. 54130803Smarcel */ 55130803Smarcel 56130803Smarcel#ifdef HAVE_CONFIG_H 57130803Smarcel# include <config.h> 58130803Smarcel#endif /* HAVE_CONFIG_H */ 59130803Smarcel#include <am_defs.h> 60130803Smarcel#include <amd.h> 61130803Smarcel 62130803Smarcelint timeout(u_int secs, void (*fn) (voidp), voidp closure); 63130803Smarcelvoid reschedule_timeouts(time_t now, time_t then); 64130803Smarcel 65130803Smarceltypedef struct callout callout; 66130803Smarcelstruct callout { 67130803Smarcel callout *c_next; /* List of callouts */ 68130803Smarcel void (*c_fn) (voidp); /* Function to call */ 69130803Smarcel voidp c_closure; /* Closure to pass to call */ 70130803Smarcel time_t c_time; /* Time of call */ 71130803Smarcel int c_id; /* Unique identifier */ 72130803Smarcel}; 73130803Smarcel 74130803Smarcelstatic callout callouts; /* List of pending callouts */ 75130803Smarcelstatic callout *free_callouts; /* Cache of free callouts */ 76130803Smarcelstatic int nfree_callouts; /* Number on free list */ 77130803Smarcelstatic int callout_id; /* Next free callout identifier */ 78130803Smarcel 79130803Smarceltime_t next_softclock; /* Time of next call to softclock() */ 80130803Smarcel 81130803Smarcel 82130803Smarcel/* 83130803Smarcel * Number of callout slots we keep on the free list 84130803Smarcel */ 85130803Smarcel#define CALLOUT_FREE_SLOP 10 86130803Smarcel 87130803Smarcel/* 88130803Smarcel * Global assumption: valid id's are non-zero. 89130803Smarcel */ 90130803Smarcel#define CID_ALLOC(struct ) (++callout_id) 91130803Smarcel#define CID_UNDEF (0) 92130803Smarcel 93130803Smarcel 94130803Smarcelstatic callout * 95130803Smarcelalloc_callout(void) 96130803Smarcel{ 97130803Smarcel callout *cp = free_callouts; 98130803Smarcel 99130803Smarcel if (cp) { 100130803Smarcel --nfree_callouts; 101130803Smarcel free_callouts = free_callouts->c_next; 102130803Smarcel return cp; 103130803Smarcel } 104130803Smarcel return ALLOC(struct callout); 105130803Smarcel} 106130803Smarcel 107130803Smarcel 108130803Smarcelstatic void 109130803Smarcelfree_callout(callout *cp) 110130803Smarcel{ 111130803Smarcel if (nfree_callouts > CALLOUT_FREE_SLOP) { 112130803Smarcel XFREE(cp); 113130803Smarcel } else { 114130803Smarcel cp->c_next = free_callouts; 115130803Smarcel free_callouts = cp; 116130803Smarcel nfree_callouts++; 117130803Smarcel } 118130803Smarcel} 119130803Smarcel 120130803Smarcel 121130803Smarcel/* 122130803Smarcel * Schedule a callout. 123130803Smarcel * 124130803Smarcel * (*fn)(closure) will be called at clocktime() + secs 125130803Smarcel */ 126130803Smarcelint 127130803Smarceltimeout(u_int secs, void (*fn) (voidp), voidp closure) 128130803Smarcel{ 129130803Smarcel callout *cp, *cp2; 130130803Smarcel time_t t = clocktime() + secs; 131130803Smarcel 132130803Smarcel /* 133130803Smarcel * Allocate and fill in a new callout structure 134130803Smarcel */ 135130803Smarcel callout *cpnew = alloc_callout(); 136130803Smarcel cpnew->c_closure = closure; 137130803Smarcel cpnew->c_fn = fn; 138130803Smarcel cpnew->c_time = t; 139130803Smarcel cpnew->c_id = CID_ALLOC(struct ); 140130803Smarcel 141130803Smarcel if (t < next_softclock) 142130803Smarcel next_softclock = t; 143130803Smarcel 144130803Smarcel /* 145130803Smarcel * Find the correct place in the list 146130803Smarcel */ 147130803Smarcel for (cp = &callouts; (cp2 = cp->c_next); cp = cp2) 148130803Smarcel if (cp2->c_time >= t) 149130803Smarcel break; 150130803Smarcel 151130803Smarcel /* 152130803Smarcel * And link it in 153130803Smarcel */ 154130803Smarcel cp->c_next = cpnew; 155130803Smarcel cpnew->c_next = cp2; 156130803Smarcel 157130803Smarcel /* 158130803Smarcel * Return callout identifier 159130803Smarcel */ 160130803Smarcel return cpnew->c_id; 161130803Smarcel} 162130803Smarcel 163130803Smarcel 164130803Smarcel/* 165130803Smarcel * De-schedule a callout 166130803Smarcel */ 167130803Smarcelvoid 168130803Smarceluntimeout(int id) 169130803Smarcel{ 170130803Smarcel callout *cp, *cp2; 171130803Smarcel for (cp = &callouts; (cp2 = cp->c_next); cp = cp2) { 172130803Smarcel if (cp2->c_id == id) { 173130803Smarcel cp->c_next = cp2->c_next; 174130803Smarcel free_callout(cp2); 175130803Smarcel break; 176130803Smarcel } 177130803Smarcel } 178130803Smarcel} 179130803Smarcel 180130803Smarcel 181130803Smarcel/* 182130803Smarcel * Reschedule after clock changed 183130803Smarcel */ 184130803Smarcelvoid 185130803Smarcelreschedule_timeouts(time_t now, time_t then) 186130803Smarcel{ 187130803Smarcel callout *cp; 188130803Smarcel 189130803Smarcel for (cp = callouts.c_next; cp; cp = cp->c_next) { 190130803Smarcel if (cp->c_time >= now && cp->c_time <= then) { 191130803Smarcel plog(XLOG_WARNING, "job %d rescheduled to run immediately", cp->c_id); 192130803Smarcel#ifdef DEBUG 193130803Smarcel dlog("rescheduling job %d back %d seconds", cp->c_id, cp->c_time - now); 194130803Smarcel#endif /* DEBUG */ 195130803Smarcel next_softclock = cp->c_time = now; 196130803Smarcel } 197130803Smarcel } 198130803Smarcel} 199130803Smarcel 200130803Smarcel 201130803Smarcel/* 202130803Smarcel * Clock handler 203130803Smarcel */ 204130803Smarcelint 205130803Smarcelsoftclock(void) 206130803Smarcel{ 207130803Smarcel time_t now; 208130803Smarcel callout *cp; 209130803Smarcel 210130803Smarcel do { 211130803Smarcel if (task_notify_todo) 212130803Smarcel do_task_notify(); 213130803Smarcel 214130803Smarcel now = clocktime(); 215130803Smarcel 216130803Smarcel /* 217130803Smarcel * While there are more callouts waiting... 218130803Smarcel */ 219130803Smarcel while ((cp = callouts.c_next) && cp->c_time <= now) { 220130803Smarcel /* 221130803Smarcel * Extract first from list, save fn & closure and 222130803Smarcel * unlink callout from list and free. 223130803Smarcel * Finally call function. 224130803Smarcel * 225130803Smarcel * The free is done first because 226130803Smarcel * it is quite common that the 227130803Smarcel * function will call timeout() 228130803Smarcel * and try to allocate a callout 229130803Smarcel */ 230130803Smarcel void (*fn) (voidp) = cp->c_fn; 231130803Smarcel voidp closure = cp->c_closure; 232130803Smarcel 233130803Smarcel callouts.c_next = cp->c_next; 234130803Smarcel free_callout(cp); 235130803Smarcel (*fn) (closure); 236130803Smarcel } 237130803Smarcel 238130803Smarcel } while (task_notify_todo); 239130803Smarcel 240130803Smarcel /* 241130803Smarcel * Return number of seconds to next event, 242130803Smarcel * or 0 if there is no event. 243130803Smarcel */ 244130803Smarcel if ((cp = callouts.c_next)) 245130803Smarcel return cp->c_time - now; 246130803Smarcel return 0; 247130803Smarcel} 248130803Smarcel