1 /* 2 * $Id: clock.c,v 5.2 90/06/23 22:19:21 jsp Rel $ 3 * 4 * Copyright (c) 1989 Jan-Simon Pendry 5 * Copyright (c) 1989 Imperial College of Science, Technology & Medicine 6 * Copyright (c) 1989 The Regents of the University of California. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * Jan-Simon Pendry at Imperial College, London. 11 * 12 * %sccs.include.redist.c% 13 * 14 * @(#)clock.c 5.1 (Berkeley) 06/29/90 15 */ 16 17 /* 18 * Callouts. 19 * 20 * Modelled on kernel object of the same name. 21 * See usual references. 22 * 23 * Use of a heap-based mechanism was rejected: 24 * 1. more complext implementation needed. 25 * 2. not obvious that a list is too slow for amd. 26 */ 27 28 #include "am.h" 29 30 typedef struct callout callout; 31 struct callout { 32 callout *c_next; /* List of callouts */ 33 void (*c_fn)(); /* Function to call */ 34 voidp c_closure; /* Closure to pass to call */ 35 time_t c_time; /* Time of call */ 36 int c_id; /* Unique identifier */ 37 }; 38 39 static callout callouts; /* List of pending callouts */ 40 static callout *free_callouts; /* Cache of free callouts */ 41 static int nfree_callouts; /* Number on free list */ 42 static int callout_id; /* Next free callout identifier */ 43 time_t next_softclock; /* Time of next call to softclock() */ 44 45 /* 46 * Number of callout slots we keep on the free list 47 */ 48 #define CALLOUT_FREE_SLOP 10 49 50 /* 51 * Assumption: valid id's are non-zero. 52 */ 53 #define CID_ALLOC() (++callout_id) 54 #define CID_UNDEF (0) 55 56 static callout *alloc_callout() 57 { 58 callout *cp = free_callouts; 59 if (cp) { 60 --nfree_callouts; 61 free_callouts = free_callouts->c_next; 62 return cp; 63 } 64 return ALLOC(callout); 65 } 66 67 static void free_callout(cp) 68 callout *cp; 69 { 70 if (nfree_callouts > CALLOUT_FREE_SLOP) { 71 free((voidp) cp); 72 } else { 73 cp->c_next = free_callouts; 74 free_callouts = cp; 75 nfree_callouts++; 76 } 77 } 78 79 /* 80 * Schedule a callout. 81 * 82 * (*fn)(closure) will be called at clocktime() + secs 83 */ 84 int timeout(secs, fn, closure) 85 unsigned int secs; 86 void (*fn)(); 87 voidp closure; 88 { 89 callout *cp, *cp2; 90 time_t t = clocktime() + secs; 91 92 /* 93 * Allocate and fill in a new callout structure 94 */ 95 callout *cpnew = alloc_callout(); 96 cpnew->c_closure = closure; 97 cpnew->c_fn = fn; 98 cpnew->c_time = t; 99 cpnew->c_id = CID_ALLOC(); 100 101 if (t < next_softclock) 102 next_softclock = t; 103 104 /* 105 * Find the correct place in the list 106 */ 107 for (cp = &callouts; cp2 = cp->c_next; cp = cp2) 108 if (cp2->c_time >= t) 109 break; 110 111 /* 112 * And link it in 113 */ 114 cp->c_next = cpnew; 115 cpnew->c_next = cp2; 116 117 /* 118 * Return callout identifier 119 */ 120 return cpnew->c_id; 121 } 122 123 /* 124 * De-schedule a callout 125 */ 126 void untimeout(id) 127 int id; 128 { 129 callout *cp, *cp2; 130 for (cp = &callouts; cp2 = cp->c_next; cp = cp2) { 131 if (cp2->c_id == id) { 132 cp->c_next = cp2->c_next; 133 free_callout(cp2); 134 break; 135 } 136 } 137 } 138 139 /* 140 * Clock handler 141 */ 142 int softclock() 143 { 144 time_t now; 145 callout *cp; 146 147 do { 148 if (task_notify_todo) 149 task_notify(); 150 151 now = clocktime(); 152 153 /* 154 * While there are more callouts waiting... 155 */ 156 while ((cp = callouts.c_next) && cp->c_time <= now) { 157 /* 158 * Extract first from list, save fn & closure and 159 * unlink callout from list and free. 160 * Finally call function. 161 * 162 * The free is done first because 163 * it is quite common that the 164 * function will call timeout() 165 * and try to allocate a callout 166 */ 167 void (*fn)() = cp->c_fn; 168 voidp closure = cp->c_closure; 169 170 callouts.c_next = cp->c_next; 171 free_callout(cp); 172 #ifdef DEBUG 173 /*dlog("Calling %#x(%#x)", fn, closure);*/ 174 #endif /* DEBUG */ 175 (*fn)(closure); 176 } 177 178 } while (task_notify_todo); 179 180 /* 181 * Return number of seconds to next event, 182 * or 0 if there is no event. 183 */ 184 if (cp = callouts.c_next) 185 return cp->c_time - now; 186 return 0; 187 } 188