1 /* 2 * Copyright (c) 1990 Jan-Simon Pendry 3 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 4 * Copyright (c) 1990, 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 * %sccs.include.redist.c% 11 * 12 * @(#)sched.c 8.1 (Berkeley) 06/06/93 13 * 14 * $Id: sched.c,v 5.2.2.1 1992/02/09 15:09:02 jsp beta $ 15 * 16 */ 17 18 /* 19 * Process scheduler 20 */ 21 22 #include "am.h" 23 #include <sys/signal.h> 24 #include WAIT 25 #include <setjmp.h> 26 extern jmp_buf select_intr; 27 extern int select_intr_valid; 28 29 typedef struct pjob pjob; 30 struct pjob { 31 qelem hdr; /* Linked list */ 32 int pid; /* Process ID of job */ 33 cb_fun cb_fun; /* Callback function */ 34 voidp cb_closure; /* Closure for callback */ 35 union wait w; /* Status filled in by sigchld */ 36 voidp wchan; /* Wait channel */ 37 }; 38 39 extern qelem proc_list_head; 40 qelem proc_list_head = { &proc_list_head, &proc_list_head }; 41 extern qelem proc_wait_list; 42 qelem proc_wait_list = { &proc_wait_list, &proc_wait_list }; 43 44 int task_notify_todo; 45 46 void ins_que(elem, pred) 47 qelem *elem, *pred; 48 { 49 qelem *p = pred->q_forw; 50 elem->q_back = pred; 51 elem->q_forw = p; 52 pred->q_forw = elem; 53 p->q_back = elem; 54 } 55 56 void rem_que(elem) 57 qelem *elem; 58 { 59 qelem *p = elem->q_forw; 60 qelem *p2 = elem->q_back; 61 p2->q_forw = p; 62 p->q_back = p2; 63 } 64 65 static pjob *sched_job(cf, ca) 66 cb_fun cf; 67 voidp ca; 68 { 69 pjob *p = ALLOC(pjob); 70 71 p->cb_fun = cf; 72 p->cb_closure = ca; 73 74 /* 75 * Now place on wait queue 76 */ 77 ins_que(&p->hdr, &proc_wait_list); 78 79 return p; 80 } 81 82 void run_task(tf, ta, cf, ca) 83 task_fun tf; 84 voidp ta; 85 cb_fun cf; 86 voidp ca; 87 { 88 pjob *p = sched_job(cf, ca); 89 int mask; 90 91 p->wchan = (voidp) p; 92 93 mask = sigblock(sigmask(SIGCHLD)); 94 95 if (p->pid = background()) { 96 sigsetmask(mask); 97 return; 98 } 99 100 exit((*tf)(ta)); 101 /* firewall... */ 102 abort(); 103 } 104 105 /* 106 * Schedule a task to be run when woken up 107 */ 108 void sched_task(cf, ca, wchan) 109 cb_fun cf; 110 voidp ca; 111 voidp wchan; 112 { 113 /* 114 * Allocate a new task 115 */ 116 pjob *p = sched_job(cf, ca); 117 #ifdef DEBUG_SLEEP 118 dlog("SLEEP on %#x", wchan); 119 #endif 120 p->wchan = wchan; 121 p->pid = 0; 122 bzero((voidp) &p->w, sizeof(p->w)); 123 } 124 125 static void wakeupjob(p) 126 pjob *p; 127 { 128 rem_que(&p->hdr); 129 ins_que(&p->hdr, &proc_list_head); 130 task_notify_todo++; 131 } 132 133 void wakeup(wchan) 134 voidp wchan; 135 { 136 pjob *p, *p2; 137 #ifdef DEBUG_SLEEP 138 int done = 0; 139 #endif 140 if (!foreground) 141 return; 142 143 #ifdef DEBUG_SLEEP 144 /*dlog("wakeup(%#x)", wchan);*/ 145 #endif 146 /* 147 * Can't user ITER() here because 148 * wakeupjob() juggles the list. 149 */ 150 for (p = FIRST(pjob, &proc_wait_list); 151 p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list); 152 p = p2) { 153 if (p->wchan == wchan) { 154 #ifdef DEBUG_SLEEP 155 done = 1; 156 #endif 157 wakeupjob(p); 158 } 159 } 160 161 #ifdef DEBUG_SLEEP 162 if (!done) 163 dlog("Nothing SLEEPing on %#x", wchan); 164 #endif 165 } 166 167 void wakeup_task(rc, term, cl) 168 int rc; 169 int term; 170 voidp cl; 171 { 172 wakeup(cl); 173 } 174 175 /*ARGSUSED*/ 176 177 void sigchld(sig) 178 int sig; 179 { 180 union wait w; 181 int pid; 182 183 #ifdef SYS5_SIGNALS 184 if ((pid = wait(&w)) > 0) { 185 #else 186 while ((pid = wait3((int *) &w, WNOHANG, (struct rusage *) 0)) > 0) { 187 #endif /* SYS5_SIGNALS */ 188 pjob *p, *p2; 189 190 if (WIFSIGNALED(w)) 191 plog(XLOG_ERROR, "Process %d exited with signal %d", 192 pid, w.w_termsig); 193 #ifdef DEBUG 194 else 195 dlog("Process %d exited with status %d", 196 pid, w.w_retcode); 197 #endif /* DEBUG */ 198 199 for (p = FIRST(pjob, &proc_wait_list); 200 p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list); 201 p = p2) { 202 if (p->pid == pid) { 203 p->w = w; 204 wakeupjob(p); 205 break; 206 } 207 } 208 209 #ifdef DEBUG 210 if (p) ; else dlog("can't locate task block for pid %d", pid); 211 #endif /* DEBUG */ 212 } 213 214 #ifdef SYS5_SIGNALS 215 signal(sig, sigchld); 216 #endif /* SYS5_SIGNALS */ 217 if (select_intr_valid) 218 longjmp(select_intr, sig); 219 } 220 221 /* 222 * Run any pending tasks. 223 * This must be called with SIGCHLD disabled 224 */ 225 void do_task_notify(P_void) 226 { 227 /* 228 * Keep taking the first item off the list and processing it. 229 * 230 * Done this way because the the callback can, quite reasonably, 231 * queue a new task, so no local reference into the list can be 232 * held here. 233 */ 234 while (FIRST(pjob, &proc_list_head) != HEAD(pjob, &proc_list_head)) { 235 pjob *p = FIRST(pjob, &proc_list_head); 236 rem_que(&p->hdr); 237 /* 238 * This job has completed 239 */ 240 --task_notify_todo; 241 242 /* 243 * Do callback if it exists 244 */ 245 if (p->cb_fun) 246 (*p->cb_fun)(p->w.w_retcode, 247 p->w.w_termsig, p->cb_closure); 248 249 free((voidp) p); 250 } 251 } 252 253 #ifdef HAS_SVR3_SIGNALS 254 /* 255 * 4.2 signal library based on svr3 (4.1+ bsd) interface 256 * From Stephen C. Pope <scp@acl.lanl.gov). 257 */ 258 259 static int current_mask = 0; 260 261 int sigblock(mask) 262 int mask; 263 { 264 int sig; 265 int m; 266 int oldmask; 267 268 oldmask = current_mask; 269 for ( sig = 1, m = 1; sig <= MAXSIG; sig++, m <<= 1 ) { 270 if (mask & m) { 271 sighold(sig); 272 current_mask |= m; 273 } 274 } 275 return oldmask; 276 } 277 278 int sigsetmask(mask) 279 int mask; 280 { 281 int sig; 282 int m; 283 int oldmask; 284 285 oldmask = current_mask; 286 for ( sig = 1, m = 1; sig <= MAXSIG; sig++, m <<= 1 ) { 287 if (mask & m) { 288 sighold(sig); 289 current_mask |= m; 290 } 291 else { 292 sigrelse(sig); 293 current_mask &= ~m; 294 } 295 } 296 return oldmask; 297 } 298 299 #endif /* HAS_SVR3_SIGNALS */ 300