sched.c revision 42629
1/* 2 * Copyright (c) 1997-1998 Erez Zadok 3 * Copyright (c) 1990 Jan-Simon Pendry 4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 5 * Copyright (c) 1990 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 * %W% (Berkeley) %G% 40 * 41 * $Id: sched.c,v 1.1.1.1 1998/11/05 02:04:49 ezk Exp $ 42 * 43 */ 44 45/* 46 * Process scheduler 47 */ 48 49#ifdef HAVE_CONFIG_H 50# include <config.h> 51#endif /* HAVE_CONFIG_H */ 52#include <am_defs.h> 53#include <amd.h> 54 55 56typedef struct pjob pjob; 57 58struct pjob { 59 qelem hdr; /* Linked list */ 60 int pid; /* Process ID of job */ 61 cb_fun cb_fun; /* Callback function */ 62 voidp cb_closure; /* Closure for callback */ 63 int w; /* everyone these days uses int, not a "union wait" */ 64 voidp wchan; /* Wait channel */ 65}; 66 67/* globals */ 68qelem proc_list_head = {&proc_list_head, &proc_list_head}; 69qelem proc_wait_list = {&proc_wait_list, &proc_wait_list}; 70int task_notify_todo; 71 72 73void 74ins_que(qelem *elem, qelem *pred) 75{ 76 qelem *p = pred->q_forw; 77 78 elem->q_back = pred; 79 elem->q_forw = p; 80 pred->q_forw = elem; 81 p->q_back = elem; 82} 83 84 85void 86rem_que(qelem *elem) 87{ 88 qelem *p = elem->q_forw; 89 qelem *p2 = elem->q_back; 90 91 p2->q_forw = p; 92 p->q_back = p2; 93} 94 95 96static pjob * 97sched_job(cb_fun cf, voidp ca) 98{ 99 pjob *p = ALLOC(struct pjob); 100 101 p->cb_fun = cf; 102 p->cb_closure = ca; 103 104 /* 105 * Now place on wait queue 106 */ 107 ins_que(&p->hdr, &proc_wait_list); 108 109 return p; 110} 111 112 113/* 114 * tf: The task to execute (ta is its arguments) 115 * cf: Continuation function (ca is its arguments) 116 */ 117void 118run_task(task_fun tf, voidp ta, cb_fun cf, voidp ca) 119{ 120 pjob *p = sched_job(cf, ca); 121#ifdef HAVE_SIGACTION 122 sigset_t new, mask; 123#else /* not HAVE_SIGACTION */ 124 int mask; 125#endif /* not HAVE_SIGACTION */ 126 127 p->wchan = (voidp) p; 128 129#ifdef HAVE_SIGACTION 130 sigemptyset(&new); /* initialize signal set we wish to block */ 131 sigaddset(&new, SIGCHLD); /* only block on SIGCHLD */ 132 sigprocmask(SIG_BLOCK, &new, &mask); 133#else /* not HAVE_SIGACTION */ 134 mask = sigblock(sigmask(SIGCHLD)); 135#endif /* not HAVE_SIGACTION */ 136 137 if ((p->pid = background())) { 138#ifdef HAVE_SIGACTION 139 sigprocmask(SIG_SETMASK, &mask, NULL); 140#else /* not HAVE_SIGACTION */ 141 sigsetmask(mask); 142#endif /* not HAVE_SIGACTION */ 143 return; 144 } 145 146 /* child code runs here, parent have returned to caller */ 147 148 exit((*tf) (ta)); 149 /* firewall... */ 150 abort(); 151} 152 153 154/* 155 * Schedule a task to be run when woken up 156 */ 157void 158sched_task(cb_fun cf, voidp ca, voidp wchan) 159{ 160 /* 161 * Allocate a new task 162 */ 163 pjob *p = sched_job(cf, ca); 164 165#ifdef DEBUG 166 dlog("SLEEP on %#x", wchan); 167#endif /* DEBUG */ 168 p->wchan = wchan; 169 p->pid = 0; 170 memset((voidp) &p->w, 0, sizeof(p->w)); 171} 172 173 174static void 175wakeupjob(pjob *p) 176{ 177 rem_que(&p->hdr); 178 ins_que(&p->hdr, &proc_list_head); 179 task_notify_todo++; 180} 181 182 183void 184wakeup(voidp wchan) 185{ 186 pjob *p, *p2; 187 188 if (!foreground) 189 return; 190 191 /* 192 * Can't user ITER() here because 193 * wakeupjob() juggles the list. 194 */ 195 for (p = AM_FIRST(pjob, &proc_wait_list); 196 p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list); 197 p = p2) { 198 if (p->wchan == wchan) { 199 wakeupjob(p); 200 } 201 } 202} 203 204 205void 206wakeup_task(int rc, int term, voidp cl) 207{ 208 wakeup(cl); 209} 210 211 212/* 213 * Run any pending tasks. 214 * This must be called with SIGCHLD disabled 215 */ 216void 217do_task_notify(void) 218{ 219 /* 220 * Keep taking the first item off the list and processing it. 221 * 222 * Done this way because the the callback can, quite reasonably, 223 * queue a new task, so no local reference into the list can be 224 * held here. 225 */ 226 while (AM_FIRST(pjob, &proc_list_head) != HEAD(pjob, &proc_list_head)) { 227 pjob *p = AM_FIRST(pjob, &proc_list_head); 228 rem_que(&p->hdr); 229 /* 230 * This job has completed 231 */ 232 --task_notify_todo; 233 234 /* 235 * Do callback if it exists 236 */ 237 if (p->cb_fun) { 238 /* these two trigraphs will ensure compatibility with strict POSIX.1 */ 239 (*p->cb_fun) (WIFEXITED(p->w) ? WEXITSTATUS(p->w) : 0, 240 WIFSIGNALED(p->w) ? WTERMSIG(p->w) : 0, 241 p->cb_closure); 242 } 243 XFREE(p); 244 } 245} 246 247 248RETSIGTYPE 249sigchld(int sig) 250{ 251 int w; /* everyone these days uses int, not a "union wait" */ 252 int pid; 253 254#ifdef HAVE_WAITPID 255 while ((pid = waitpid((pid_t) -1, &w, WNOHANG)) > 0) { 256#else /* not HAVE_WAITPID */ 257 while ((pid = wait3( &w, WNOHANG, (struct rusage *) 0)) > 0) { 258#endif /* not HAVE_WAITPID */ 259 pjob *p, *p2; 260 261 if (WIFSIGNALED(w)) 262 plog(XLOG_ERROR, "Process %d exited with signal %d", 263 pid, WTERMSIG(w)); 264#ifdef DEBUG 265 else 266 dlog("Process %d exited with status %d", 267 pid, WEXITSTATUS(w)); 268#endif /* DEBUG */ 269 270 for (p = AM_FIRST(pjob, &proc_wait_list); 271 p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list); 272 p = p2) { 273 if (p->pid == pid) { 274 p->w = w; 275 wakeupjob(p); 276 break; 277 } 278 } /* end of for loop */ 279 280#ifdef DEBUG 281 if (!p) 282 dlog("can't locate task block for pid %d", pid); 283#endif /* DEBUG */ 284 285 /* 286 * Must count down children inside the while loop, otherwise we won't 287 * count them all, and NumChild (and later backoff) will be set 288 * incorrectly. SH/RUNIT 940519. 289 */ 290 if (--NumChild < 0) 291 NumChild = 0; 292 } /* end of "while wait..." loop */ 293 294#ifdef REINSTALL_SIGNAL_HANDLER 295 signal(sig, sigchld); 296#endif /* REINSTALL_SIGNAL_HANDLER */ 297 298 if (select_intr_valid) 299 longjmp(select_intr, sig); 300} 301