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