1*a53f50b9Schristos /* $NetBSD: sched.c,v 1.1.1.1 2008/09/19 20:07:17 christos Exp $ */ 2*a53f50b9Schristos 3*a53f50b9Schristos /* 4*a53f50b9Schristos * Copyright (c) 1997-2007 Erez Zadok 5*a53f50b9Schristos * Copyright (c) 1990 Jan-Simon Pendry 6*a53f50b9Schristos * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 7*a53f50b9Schristos * Copyright (c) 1990 The Regents of the University of California. 8*a53f50b9Schristos * All rights reserved. 9*a53f50b9Schristos * 10*a53f50b9Schristos * This code is derived from software contributed to Berkeley by 11*a53f50b9Schristos * Jan-Simon Pendry at Imperial College, London. 12*a53f50b9Schristos * 13*a53f50b9Schristos * Redistribution and use in source and binary forms, with or without 14*a53f50b9Schristos * modification, are permitted provided that the following conditions 15*a53f50b9Schristos * are met: 16*a53f50b9Schristos * 1. Redistributions of source code must retain the above copyright 17*a53f50b9Schristos * notice, this list of conditions and the following disclaimer. 18*a53f50b9Schristos * 2. Redistributions in binary form must reproduce the above copyright 19*a53f50b9Schristos * notice, this list of conditions and the following disclaimer in the 20*a53f50b9Schristos * documentation and/or other materials provided with the distribution. 21*a53f50b9Schristos * 3. All advertising materials mentioning features or use of this software 22*a53f50b9Schristos * must display the following acknowledgment: 23*a53f50b9Schristos * This product includes software developed by the University of 24*a53f50b9Schristos * California, Berkeley and its contributors. 25*a53f50b9Schristos * 4. Neither the name of the University nor the names of its contributors 26*a53f50b9Schristos * may be used to endorse or promote products derived from this software 27*a53f50b9Schristos * without specific prior written permission. 28*a53f50b9Schristos * 29*a53f50b9Schristos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30*a53f50b9Schristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31*a53f50b9Schristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32*a53f50b9Schristos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33*a53f50b9Schristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34*a53f50b9Schristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35*a53f50b9Schristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36*a53f50b9Schristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37*a53f50b9Schristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38*a53f50b9Schristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39*a53f50b9Schristos * SUCH DAMAGE. 40*a53f50b9Schristos * 41*a53f50b9Schristos * 42*a53f50b9Schristos * File: am-utils/amd/sched.c 43*a53f50b9Schristos * 44*a53f50b9Schristos */ 45*a53f50b9Schristos 46*a53f50b9Schristos /* 47*a53f50b9Schristos * Process scheduler 48*a53f50b9Schristos */ 49*a53f50b9Schristos 50*a53f50b9Schristos #ifdef HAVE_CONFIG_H 51*a53f50b9Schristos # include <config.h> 52*a53f50b9Schristos #endif /* HAVE_CONFIG_H */ 53*a53f50b9Schristos #include <am_defs.h> 54*a53f50b9Schristos #include <amd.h> 55*a53f50b9Schristos 56*a53f50b9Schristos 57*a53f50b9Schristos typedef struct pjob pjob; 58*a53f50b9Schristos 59*a53f50b9Schristos struct pjob { 60*a53f50b9Schristos qelem hdr; /* Linked list */ 61*a53f50b9Schristos int pid; /* Process ID of job */ 62*a53f50b9Schristos cb_fun *cb_fun; /* Callback function */ 63*a53f50b9Schristos opaque_t cb_arg; /* Argument for callback */ 64*a53f50b9Schristos int w; /* everyone these days uses int, not a "union wait" */ 65*a53f50b9Schristos wchan_t wchan; /* Wait channel */ 66*a53f50b9Schristos }; 67*a53f50b9Schristos 68*a53f50b9Schristos /* globals */ 69*a53f50b9Schristos qelem proc_list_head = {&proc_list_head, &proc_list_head}; 70*a53f50b9Schristos qelem proc_wait_list = {&proc_wait_list, &proc_wait_list}; 71*a53f50b9Schristos int task_notify_todo; 72*a53f50b9Schristos 73*a53f50b9Schristos 74*a53f50b9Schristos void 75*a53f50b9Schristos ins_que(qelem *elem, qelem *pred) 76*a53f50b9Schristos { 77*a53f50b9Schristos qelem *p = pred->q_forw; 78*a53f50b9Schristos 79*a53f50b9Schristos elem->q_back = pred; 80*a53f50b9Schristos elem->q_forw = p; 81*a53f50b9Schristos pred->q_forw = elem; 82*a53f50b9Schristos p->q_back = elem; 83*a53f50b9Schristos } 84*a53f50b9Schristos 85*a53f50b9Schristos 86*a53f50b9Schristos void 87*a53f50b9Schristos rem_que(qelem *elem) 88*a53f50b9Schristos { 89*a53f50b9Schristos qelem *p = elem->q_forw; 90*a53f50b9Schristos qelem *p2 = elem->q_back; 91*a53f50b9Schristos 92*a53f50b9Schristos p2->q_forw = p; 93*a53f50b9Schristos p->q_back = p2; 94*a53f50b9Schristos } 95*a53f50b9Schristos 96*a53f50b9Schristos 97*a53f50b9Schristos static pjob * 98*a53f50b9Schristos sched_job(cb_fun *cf, opaque_t ca) 99*a53f50b9Schristos { 100*a53f50b9Schristos pjob *p = ALLOC(struct pjob); 101*a53f50b9Schristos 102*a53f50b9Schristos p->cb_fun = cf; 103*a53f50b9Schristos p->cb_arg = ca; 104*a53f50b9Schristos 105*a53f50b9Schristos /* 106*a53f50b9Schristos * Now place on wait queue 107*a53f50b9Schristos */ 108*a53f50b9Schristos ins_que(&p->hdr, &proc_wait_list); 109*a53f50b9Schristos 110*a53f50b9Schristos return p; 111*a53f50b9Schristos } 112*a53f50b9Schristos 113*a53f50b9Schristos 114*a53f50b9Schristos /* 115*a53f50b9Schristos * tf: The task to execute (ta is its arguments) 116*a53f50b9Schristos * cf: Continuation function (ca is its arguments) 117*a53f50b9Schristos */ 118*a53f50b9Schristos void 119*a53f50b9Schristos run_task(task_fun *tf, opaque_t ta, cb_fun *cf, opaque_t ca) 120*a53f50b9Schristos { 121*a53f50b9Schristos pjob *p = sched_job(cf, ca); 122*a53f50b9Schristos #ifdef HAVE_SIGACTION 123*a53f50b9Schristos sigset_t new, mask; 124*a53f50b9Schristos #else /* not HAVE_SIGACTION */ 125*a53f50b9Schristos int mask; 126*a53f50b9Schristos #endif /* not HAVE_SIGACTION */ 127*a53f50b9Schristos 128*a53f50b9Schristos p->wchan = (wchan_t) p; 129*a53f50b9Schristos 130*a53f50b9Schristos #ifdef HAVE_SIGACTION 131*a53f50b9Schristos sigemptyset(&new); /* initialize signal set we wish to block */ 132*a53f50b9Schristos sigaddset(&new, SIGCHLD); /* only block on SIGCHLD */ 133*a53f50b9Schristos sigprocmask(SIG_BLOCK, &new, &mask); 134*a53f50b9Schristos #else /* not HAVE_SIGACTION */ 135*a53f50b9Schristos mask = sigblock(sigmask(SIGCHLD)); 136*a53f50b9Schristos #endif /* not HAVE_SIGACTION */ 137*a53f50b9Schristos 138*a53f50b9Schristos if ((p->pid = background())) { 139*a53f50b9Schristos #ifdef HAVE_SIGACTION 140*a53f50b9Schristos sigprocmask(SIG_SETMASK, &mask, NULL); 141*a53f50b9Schristos #else /* not HAVE_SIGACTION */ 142*a53f50b9Schristos sigsetmask(mask); 143*a53f50b9Schristos #endif /* not HAVE_SIGACTION */ 144*a53f50b9Schristos return; 145*a53f50b9Schristos } 146*a53f50b9Schristos 147*a53f50b9Schristos /* child code runs here, parent has returned to caller */ 148*a53f50b9Schristos 149*a53f50b9Schristos exit((*tf) (ta)); 150*a53f50b9Schristos /* firewall... */ 151*a53f50b9Schristos abort(); 152*a53f50b9Schristos } 153*a53f50b9Schristos 154*a53f50b9Schristos 155*a53f50b9Schristos /* 156*a53f50b9Schristos * Schedule a task to be run when woken up 157*a53f50b9Schristos */ 158*a53f50b9Schristos void 159*a53f50b9Schristos sched_task(cb_fun *cf, opaque_t ca, wchan_t wchan) 160*a53f50b9Schristos { 161*a53f50b9Schristos /* 162*a53f50b9Schristos * Allocate a new task 163*a53f50b9Schristos */ 164*a53f50b9Schristos pjob *p = sched_job(cf, ca); 165*a53f50b9Schristos 166*a53f50b9Schristos dlog("SLEEP on %p", wchan); 167*a53f50b9Schristos p->wchan = wchan; 168*a53f50b9Schristos p->pid = 0; 169*a53f50b9Schristos p->w = 0; /* was memset (when ->w was union) */ 170*a53f50b9Schristos } 171*a53f50b9Schristos 172*a53f50b9Schristos 173*a53f50b9Schristos static void 174*a53f50b9Schristos wakeupjob(pjob *p) 175*a53f50b9Schristos { 176*a53f50b9Schristos rem_que(&p->hdr); 177*a53f50b9Schristos ins_que(&p->hdr, &proc_list_head); 178*a53f50b9Schristos task_notify_todo++; 179*a53f50b9Schristos } 180*a53f50b9Schristos 181*a53f50b9Schristos 182*a53f50b9Schristos void 183*a53f50b9Schristos wakeup(wchan_t wchan) 184*a53f50b9Schristos { 185*a53f50b9Schristos pjob *p, *p2; 186*a53f50b9Schristos 187*a53f50b9Schristos if (!foreground) 188*a53f50b9Schristos return; 189*a53f50b9Schristos 190*a53f50b9Schristos /* 191*a53f50b9Schristos * Can't use ITER() here because 192*a53f50b9Schristos * wakeupjob() juggles the list. 193*a53f50b9Schristos */ 194*a53f50b9Schristos for (p = AM_FIRST(pjob, &proc_wait_list); 195*a53f50b9Schristos p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list); 196*a53f50b9Schristos p = p2) { 197*a53f50b9Schristos if (p->wchan == wchan) { 198*a53f50b9Schristos wakeupjob(p); 199*a53f50b9Schristos } 200*a53f50b9Schristos } 201*a53f50b9Schristos } 202*a53f50b9Schristos 203*a53f50b9Schristos 204*a53f50b9Schristos void 205*a53f50b9Schristos wakeup_task(int rc, int term, wchan_t wchan) 206*a53f50b9Schristos { 207*a53f50b9Schristos wakeup(wchan); 208*a53f50b9Schristos } 209*a53f50b9Schristos 210*a53f50b9Schristos 211*a53f50b9Schristos wchan_t 212*a53f50b9Schristos get_mntfs_wchan(mntfs *mf) 213*a53f50b9Schristos { 214*a53f50b9Schristos if (mf && 215*a53f50b9Schristos mf->mf_ops && 216*a53f50b9Schristos mf->mf_ops->get_wchan) 217*a53f50b9Schristos return mf->mf_ops->get_wchan(mf); 218*a53f50b9Schristos return mf; 219*a53f50b9Schristos } 220*a53f50b9Schristos 221*a53f50b9Schristos 222*a53f50b9Schristos /* 223*a53f50b9Schristos * Run any pending tasks. 224*a53f50b9Schristos * This must be called with SIGCHLD disabled 225*a53f50b9Schristos */ 226*a53f50b9Schristos void 227*a53f50b9Schristos do_task_notify(void) 228*a53f50b9Schristos { 229*a53f50b9Schristos /* 230*a53f50b9Schristos * Keep taking the first item off the list and processing it. 231*a53f50b9Schristos * 232*a53f50b9Schristos * Done this way because the callback can, quite reasonably, 233*a53f50b9Schristos * queue a new task, so no local reference into the list can be 234*a53f50b9Schristos * held here. 235*a53f50b9Schristos */ 236*a53f50b9Schristos while (AM_FIRST(pjob, &proc_list_head) != HEAD(pjob, &proc_list_head)) { 237*a53f50b9Schristos pjob *p = AM_FIRST(pjob, &proc_list_head); 238*a53f50b9Schristos rem_que(&p->hdr); 239*a53f50b9Schristos /* 240*a53f50b9Schristos * This job has completed 241*a53f50b9Schristos */ 242*a53f50b9Schristos --task_notify_todo; 243*a53f50b9Schristos 244*a53f50b9Schristos /* 245*a53f50b9Schristos * Do callback if it exists 246*a53f50b9Schristos */ 247*a53f50b9Schristos if (p->cb_fun) { 248*a53f50b9Schristos /* these two trigraphs will ensure compatibility with strict POSIX.1 */ 249*a53f50b9Schristos p->cb_fun(WIFEXITED(p->w) ? WEXITSTATUS(p->w) : 0, 250*a53f50b9Schristos WIFSIGNALED(p->w) ? WTERMSIG(p->w) : 0, 251*a53f50b9Schristos p->cb_arg); 252*a53f50b9Schristos } 253*a53f50b9Schristos XFREE(p); 254*a53f50b9Schristos } 255*a53f50b9Schristos } 256*a53f50b9Schristos 257*a53f50b9Schristos 258*a53f50b9Schristos RETSIGTYPE 259*a53f50b9Schristos sigchld(int sig) 260*a53f50b9Schristos { 261*a53f50b9Schristos int w; /* everyone these days uses int, not a "union wait" */ 262*a53f50b9Schristos int pid; 263*a53f50b9Schristos 264*a53f50b9Schristos #ifdef HAVE_WAITPID 265*a53f50b9Schristos while ((pid = waitpid((pid_t) -1, &w, WNOHANG)) > 0) { 266*a53f50b9Schristos #else /* not HAVE_WAITPID */ 267*a53f50b9Schristos while ((pid = wait3( &w, WNOHANG, (struct rusage *) NULL)) > 0) { 268*a53f50b9Schristos #endif /* not HAVE_WAITPID */ 269*a53f50b9Schristos pjob *p, *p2; 270*a53f50b9Schristos 271*a53f50b9Schristos if (WIFSIGNALED(w)) 272*a53f50b9Schristos plog(XLOG_ERROR, "Process %d exited with signal %d", 273*a53f50b9Schristos pid, WTERMSIG(w)); 274*a53f50b9Schristos else 275*a53f50b9Schristos dlog("Process %d exited with status %d", 276*a53f50b9Schristos pid, WEXITSTATUS(w)); 277*a53f50b9Schristos 278*a53f50b9Schristos for (p = AM_FIRST(pjob, &proc_wait_list); 279*a53f50b9Schristos p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list); 280*a53f50b9Schristos p = p2) { 281*a53f50b9Schristos if (p->pid == pid) { 282*a53f50b9Schristos p->w = w; 283*a53f50b9Schristos wakeupjob(p); 284*a53f50b9Schristos break; 285*a53f50b9Schristos } 286*a53f50b9Schristos } /* end of for loop */ 287*a53f50b9Schristos 288*a53f50b9Schristos if (p == HEAD(pjob, &proc_wait_list)) 289*a53f50b9Schristos dlog("can't locate task block for pid %d", pid); 290*a53f50b9Schristos 291*a53f50b9Schristos /* 292*a53f50b9Schristos * Must count down children inside the while loop, otherwise we won't 293*a53f50b9Schristos * count them all, and NumChildren (and later backoff) will be set 294*a53f50b9Schristos * incorrectly. SH/RUNIT 940519. 295*a53f50b9Schristos */ 296*a53f50b9Schristos if (--NumChildren < 0) 297*a53f50b9Schristos NumChildren = 0; 298*a53f50b9Schristos } /* end of "while wait..." loop */ 299*a53f50b9Schristos 300*a53f50b9Schristos #ifdef REINSTALL_SIGNAL_HANDLER 301*a53f50b9Schristos signal(sig, sigchld); 302*a53f50b9Schristos #endif /* REINSTALL_SIGNAL_HANDLER */ 303*a53f50b9Schristos 304*a53f50b9Schristos if (select_intr_valid) 305*a53f50b9Schristos longjmp(select_intr, sig); 306*a53f50b9Schristos } 307