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