sched.c revision 82794
138494Sobrien/* 282794Sobrien * Copyright (c) 1997-2001 Erez Zadok 338494Sobrien * Copyright (c) 1990 Jan-Simon Pendry 438494Sobrien * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 538494Sobrien * Copyright (c) 1990 The Regents of the University of California. 638494Sobrien * All rights reserved. 738494Sobrien * 838494Sobrien * This code is derived from software contributed to Berkeley by 938494Sobrien * Jan-Simon Pendry at Imperial College, London. 1038494Sobrien * 1138494Sobrien * Redistribution and use in source and binary forms, with or without 1238494Sobrien * modification, are permitted provided that the following conditions 1338494Sobrien * are met: 1438494Sobrien * 1. Redistributions of source code must retain the above copyright 1538494Sobrien * notice, this list of conditions and the following disclaimer. 1638494Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1738494Sobrien * notice, this list of conditions and the following disclaimer in the 1838494Sobrien * documentation and/or other materials provided with the distribution. 1938494Sobrien * 3. All advertising materials mentioning features or use of this software 2042629Sobrien * must display the following acknowledgment: 2138494Sobrien * This product includes software developed by the University of 2238494Sobrien * California, Berkeley and its contributors. 2338494Sobrien * 4. Neither the name of the University nor the names of its contributors 2438494Sobrien * may be used to endorse or promote products derived from this software 2538494Sobrien * without specific prior written permission. 2638494Sobrien * 2738494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2838494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2938494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3038494Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3138494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3238494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3338494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3438494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3538494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3638494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3738494Sobrien * SUCH DAMAGE. 3838494Sobrien * 3938494Sobrien * %W% (Berkeley) %G% 4038494Sobrien * 4182794Sobrien * $Id: sched.c,v 1.4.2.2 2001/01/10 03:23:12 ezk Exp $ 4238494Sobrien * 4338494Sobrien */ 4438494Sobrien 4538494Sobrien/* 4638494Sobrien * Process scheduler 4738494Sobrien */ 4838494Sobrien 4938494Sobrien#ifdef HAVE_CONFIG_H 5038494Sobrien# include <config.h> 5138494Sobrien#endif /* HAVE_CONFIG_H */ 5238494Sobrien#include <am_defs.h> 5338494Sobrien#include <amd.h> 5438494Sobrien 5538494Sobrien 5638494Sobrientypedef struct pjob pjob; 5738494Sobrien 5838494Sobrienstruct pjob { 5938494Sobrien qelem hdr; /* Linked list */ 6038494Sobrien int pid; /* Process ID of job */ 6138494Sobrien cb_fun cb_fun; /* Callback function */ 6238494Sobrien voidp cb_closure; /* Closure for callback */ 6338494Sobrien int w; /* everyone these days uses int, not a "union wait" */ 6438494Sobrien voidp wchan; /* Wait channel */ 6538494Sobrien}; 6638494Sobrien 6738494Sobrien/* globals */ 6838494Sobrienqelem proc_list_head = {&proc_list_head, &proc_list_head}; 6938494Sobrienqelem proc_wait_list = {&proc_wait_list, &proc_wait_list}; 7038494Sobrienint task_notify_todo; 7138494Sobrien 7238494Sobrien 7338494Sobrienvoid 7438494Sobrienins_que(qelem *elem, qelem *pred) 7538494Sobrien{ 7638494Sobrien qelem *p = pred->q_forw; 7738494Sobrien 7838494Sobrien elem->q_back = pred; 7938494Sobrien elem->q_forw = p; 8038494Sobrien pred->q_forw = elem; 8138494Sobrien p->q_back = elem; 8238494Sobrien} 8338494Sobrien 8438494Sobrien 8538494Sobrienvoid 8638494Sobrienrem_que(qelem *elem) 8738494Sobrien{ 8838494Sobrien qelem *p = elem->q_forw; 8938494Sobrien qelem *p2 = elem->q_back; 9038494Sobrien 9138494Sobrien p2->q_forw = p; 9238494Sobrien p->q_back = p2; 9338494Sobrien} 9438494Sobrien 9538494Sobrien 9638494Sobrienstatic pjob * 9738494Sobriensched_job(cb_fun cf, voidp ca) 9838494Sobrien{ 9938494Sobrien pjob *p = ALLOC(struct pjob); 10038494Sobrien 10138494Sobrien p->cb_fun = cf; 10238494Sobrien p->cb_closure = ca; 10338494Sobrien 10438494Sobrien /* 10538494Sobrien * Now place on wait queue 10638494Sobrien */ 10738494Sobrien ins_que(&p->hdr, &proc_wait_list); 10838494Sobrien 10938494Sobrien return p; 11038494Sobrien} 11138494Sobrien 11238494Sobrien 11338494Sobrien/* 11438494Sobrien * tf: The task to execute (ta is its arguments) 11538494Sobrien * cf: Continuation function (ca is its arguments) 11638494Sobrien */ 11738494Sobrienvoid 11838494Sobrienrun_task(task_fun tf, voidp ta, cb_fun cf, voidp ca) 11938494Sobrien{ 12038494Sobrien pjob *p = sched_job(cf, ca); 12138494Sobrien#ifdef HAVE_SIGACTION 12238494Sobrien sigset_t new, mask; 12338494Sobrien#else /* not HAVE_SIGACTION */ 12438494Sobrien int mask; 12538494Sobrien#endif /* not HAVE_SIGACTION */ 12638494Sobrien 12738494Sobrien p->wchan = (voidp) p; 12838494Sobrien 12938494Sobrien#ifdef HAVE_SIGACTION 13042629Sobrien sigemptyset(&new); /* initialize signal set we wish to block */ 13138494Sobrien sigaddset(&new, SIGCHLD); /* only block on SIGCHLD */ 13238494Sobrien sigprocmask(SIG_BLOCK, &new, &mask); 13338494Sobrien#else /* not HAVE_SIGACTION */ 13438494Sobrien mask = sigblock(sigmask(SIGCHLD)); 13538494Sobrien#endif /* not HAVE_SIGACTION */ 13638494Sobrien 13738494Sobrien if ((p->pid = background())) { 13838494Sobrien#ifdef HAVE_SIGACTION 13938494Sobrien sigprocmask(SIG_SETMASK, &mask, NULL); 14038494Sobrien#else /* not HAVE_SIGACTION */ 14138494Sobrien sigsetmask(mask); 14238494Sobrien#endif /* not HAVE_SIGACTION */ 14338494Sobrien return; 14438494Sobrien } 14538494Sobrien 14638494Sobrien /* child code runs here, parent have returned to caller */ 14738494Sobrien 14838494Sobrien exit((*tf) (ta)); 14938494Sobrien /* firewall... */ 15038494Sobrien abort(); 15138494Sobrien} 15238494Sobrien 15338494Sobrien 15438494Sobrien/* 15538494Sobrien * Schedule a task to be run when woken up 15638494Sobrien */ 15738494Sobrienvoid 15838494Sobriensched_task(cb_fun cf, voidp ca, voidp wchan) 15938494Sobrien{ 16038494Sobrien /* 16138494Sobrien * Allocate a new task 16238494Sobrien */ 16338494Sobrien pjob *p = sched_job(cf, ca); 16438494Sobrien 16538494Sobrien#ifdef DEBUG 16651292Sobrien dlog("SLEEP on %#lx", (unsigned long) wchan); 16738494Sobrien#endif /* DEBUG */ 16838494Sobrien p->wchan = wchan; 16938494Sobrien p->pid = 0; 17038494Sobrien memset((voidp) &p->w, 0, sizeof(p->w)); 17138494Sobrien} 17238494Sobrien 17338494Sobrien 17438494Sobrienstatic void 17538494Sobrienwakeupjob(pjob *p) 17638494Sobrien{ 17738494Sobrien rem_que(&p->hdr); 17838494Sobrien ins_que(&p->hdr, &proc_list_head); 17938494Sobrien task_notify_todo++; 18038494Sobrien} 18138494Sobrien 18238494Sobrien 18338494Sobrienvoid 18438494Sobrienwakeup(voidp wchan) 18538494Sobrien{ 18638494Sobrien pjob *p, *p2; 18738494Sobrien 18838494Sobrien if (!foreground) 18938494Sobrien return; 19038494Sobrien 19138494Sobrien /* 19238494Sobrien * Can't user ITER() here because 19338494Sobrien * wakeupjob() juggles the list. 19438494Sobrien */ 19538494Sobrien for (p = AM_FIRST(pjob, &proc_wait_list); 19638494Sobrien p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list); 19738494Sobrien p = p2) { 19838494Sobrien if (p->wchan == wchan) { 19938494Sobrien wakeupjob(p); 20038494Sobrien } 20138494Sobrien } 20238494Sobrien} 20338494Sobrien 20438494Sobrien 20538494Sobrienvoid 20638494Sobrienwakeup_task(int rc, int term, voidp cl) 20738494Sobrien{ 20838494Sobrien wakeup(cl); 20938494Sobrien} 21038494Sobrien 21138494Sobrien 21238494Sobrien/* 21338494Sobrien * Run any pending tasks. 21438494Sobrien * This must be called with SIGCHLD disabled 21538494Sobrien */ 21638494Sobrienvoid 21738494Sobriendo_task_notify(void) 21838494Sobrien{ 21938494Sobrien /* 22038494Sobrien * Keep taking the first item off the list and processing it. 22138494Sobrien * 22282794Sobrien * Done this way because the callback can, quite reasonably, 22338494Sobrien * queue a new task, so no local reference into the list can be 22438494Sobrien * held here. 22538494Sobrien */ 22638494Sobrien while (AM_FIRST(pjob, &proc_list_head) != HEAD(pjob, &proc_list_head)) { 22738494Sobrien pjob *p = AM_FIRST(pjob, &proc_list_head); 22838494Sobrien rem_que(&p->hdr); 22938494Sobrien /* 23038494Sobrien * This job has completed 23138494Sobrien */ 23238494Sobrien --task_notify_todo; 23338494Sobrien 23438494Sobrien /* 23538494Sobrien * Do callback if it exists 23638494Sobrien */ 23738494Sobrien if (p->cb_fun) { 23842629Sobrien /* these two trigraphs will ensure compatibility with strict POSIX.1 */ 23938494Sobrien (*p->cb_fun) (WIFEXITED(p->w) ? WEXITSTATUS(p->w) : 0, 24038494Sobrien WIFSIGNALED(p->w) ? WTERMSIG(p->w) : 0, 24138494Sobrien p->cb_closure); 24238494Sobrien } 24338494Sobrien XFREE(p); 24438494Sobrien } 24538494Sobrien} 24638494Sobrien 24738494Sobrien 24838494SobrienRETSIGTYPE 24938494Sobriensigchld(int sig) 25038494Sobrien{ 25138494Sobrien int w; /* everyone these days uses int, not a "union wait" */ 25238494Sobrien int pid; 25338494Sobrien 25438494Sobrien#ifdef HAVE_WAITPID 25538494Sobrien while ((pid = waitpid((pid_t) -1, &w, WNOHANG)) > 0) { 25638494Sobrien#else /* not HAVE_WAITPID */ 25738494Sobrien while ((pid = wait3( &w, WNOHANG, (struct rusage *) 0)) > 0) { 25838494Sobrien#endif /* not HAVE_WAITPID */ 25938494Sobrien pjob *p, *p2; 26038494Sobrien 26138494Sobrien if (WIFSIGNALED(w)) 26238494Sobrien plog(XLOG_ERROR, "Process %d exited with signal %d", 26338494Sobrien pid, WTERMSIG(w)); 26438494Sobrien#ifdef DEBUG 26538494Sobrien else 26638494Sobrien dlog("Process %d exited with status %d", 26738494Sobrien pid, WEXITSTATUS(w)); 26838494Sobrien#endif /* DEBUG */ 26938494Sobrien 27038494Sobrien for (p = AM_FIRST(pjob, &proc_wait_list); 27138494Sobrien p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list); 27238494Sobrien p = p2) { 27338494Sobrien if (p->pid == pid) { 27438494Sobrien p->w = w; 27538494Sobrien wakeupjob(p); 27638494Sobrien break; 27738494Sobrien } 27838494Sobrien } /* end of for loop */ 27938494Sobrien 28038494Sobrien#ifdef DEBUG 28138494Sobrien if (!p) 28238494Sobrien dlog("can't locate task block for pid %d", pid); 28338494Sobrien#endif /* DEBUG */ 28438494Sobrien 28538494Sobrien /* 28638494Sobrien * Must count down children inside the while loop, otherwise we won't 28738494Sobrien * count them all, and NumChild (and later backoff) will be set 28838494Sobrien * incorrectly. SH/RUNIT 940519. 28938494Sobrien */ 29038494Sobrien if (--NumChild < 0) 29138494Sobrien NumChild = 0; 29238494Sobrien } /* end of "while wait..." loop */ 29338494Sobrien 29438494Sobrien#ifdef REINSTALL_SIGNAL_HANDLER 29538494Sobrien signal(sig, sigchld); 29638494Sobrien#endif /* REINSTALL_SIGNAL_HANDLER */ 29738494Sobrien 29838494Sobrien if (select_intr_valid) 29938494Sobrien longjmp(select_intr, sig); 30038494Sobrien} 301