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