138494Sobrien/* 2310490Scy * Copyright (c) 1997-2014 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. 19310490Scy * 3. Neither the name of the University nor the names of its contributors 2038494Sobrien * may be used to endorse or promote products derived from this software 2138494Sobrien * without specific prior written permission. 2238494Sobrien * 2338494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2438494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2538494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2638494Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2738494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2838494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2938494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3038494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3138494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3238494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3338494Sobrien * SUCH DAMAGE. 3438494Sobrien * 3538494Sobrien * 36174294Sobrien * File: am-utils/amd/sched.c 3738494Sobrien * 3838494Sobrien */ 3938494Sobrien 4038494Sobrien/* 4138494Sobrien * Process scheduler 4238494Sobrien */ 4338494Sobrien 4438494Sobrien#ifdef HAVE_CONFIG_H 4538494Sobrien# include <config.h> 4638494Sobrien#endif /* HAVE_CONFIG_H */ 4738494Sobrien#include <am_defs.h> 4838494Sobrien#include <amd.h> 4938494Sobrien 5038494Sobrien 5138494Sobrientypedef struct pjob pjob; 5238494Sobrien 5338494Sobrienstruct pjob { 54174294Sobrien qelem hdr; /* Linked list */ 55174294Sobrien int pid; /* Process ID of job */ 56174294Sobrien cb_fun *cb_fun; /* Callback function */ 57174294Sobrien opaque_t cb_arg; /* Argument for callback */ 5838494Sobrien int w; /* everyone these days uses int, not a "union wait" */ 59174294Sobrien wchan_t wchan; /* Wait channel */ 6038494Sobrien}; 6138494Sobrien 6238494Sobrien/* globals */ 6338494Sobrienqelem proc_list_head = {&proc_list_head, &proc_list_head}; 6438494Sobrienqelem proc_wait_list = {&proc_wait_list, &proc_wait_list}; 6538494Sobrienint task_notify_todo; 6638494Sobrien 6738494Sobrien 6838494Sobrienvoid 6938494Sobrienins_que(qelem *elem, qelem *pred) 7038494Sobrien{ 7138494Sobrien qelem *p = pred->q_forw; 7238494Sobrien 7338494Sobrien elem->q_back = pred; 7438494Sobrien elem->q_forw = p; 7538494Sobrien pred->q_forw = elem; 7638494Sobrien p->q_back = elem; 7738494Sobrien} 7838494Sobrien 7938494Sobrien 8038494Sobrienvoid 8138494Sobrienrem_que(qelem *elem) 8238494Sobrien{ 8338494Sobrien qelem *p = elem->q_forw; 8438494Sobrien qelem *p2 = elem->q_back; 8538494Sobrien 8638494Sobrien p2->q_forw = p; 8738494Sobrien p->q_back = p2; 8838494Sobrien} 8938494Sobrien 9038494Sobrien 9138494Sobrienstatic pjob * 92174294Sobriensched_job(cb_fun *cf, opaque_t ca) 9338494Sobrien{ 9438494Sobrien pjob *p = ALLOC(struct pjob); 9538494Sobrien 9638494Sobrien p->cb_fun = cf; 97174294Sobrien p->cb_arg = ca; 9838494Sobrien 9938494Sobrien /* 10038494Sobrien * Now place on wait queue 10138494Sobrien */ 10238494Sobrien ins_que(&p->hdr, &proc_wait_list); 10338494Sobrien 10438494Sobrien return p; 10538494Sobrien} 10638494Sobrien 10738494Sobrien 10838494Sobrien/* 10938494Sobrien * tf: The task to execute (ta is its arguments) 11038494Sobrien * cf: Continuation function (ca is its arguments) 11138494Sobrien */ 11238494Sobrienvoid 113174294Sobrienrun_task(task_fun *tf, opaque_t ta, cb_fun *cf, opaque_t ca) 11438494Sobrien{ 11538494Sobrien pjob *p = sched_job(cf, ca); 11638494Sobrien#ifdef HAVE_SIGACTION 11738494Sobrien sigset_t new, mask; 11838494Sobrien#else /* not HAVE_SIGACTION */ 11938494Sobrien int mask; 12038494Sobrien#endif /* not HAVE_SIGACTION */ 12138494Sobrien 122174294Sobrien p->wchan = (wchan_t) p; 12338494Sobrien 12438494Sobrien#ifdef HAVE_SIGACTION 12542629Sobrien sigemptyset(&new); /* initialize signal set we wish to block */ 12638494Sobrien sigaddset(&new, SIGCHLD); /* only block on SIGCHLD */ 12738494Sobrien sigprocmask(SIG_BLOCK, &new, &mask); 12838494Sobrien#else /* not HAVE_SIGACTION */ 12938494Sobrien mask = sigblock(sigmask(SIGCHLD)); 13038494Sobrien#endif /* not HAVE_SIGACTION */ 13138494Sobrien 13238494Sobrien if ((p->pid = background())) { 13338494Sobrien#ifdef HAVE_SIGACTION 13438494Sobrien sigprocmask(SIG_SETMASK, &mask, NULL); 13538494Sobrien#else /* not HAVE_SIGACTION */ 13638494Sobrien sigsetmask(mask); 13738494Sobrien#endif /* not HAVE_SIGACTION */ 13838494Sobrien return; 13938494Sobrien } 14038494Sobrien 141174294Sobrien /* child code runs here, parent has returned to caller */ 14238494Sobrien 14338494Sobrien exit((*tf) (ta)); 14438494Sobrien /* firewall... */ 14538494Sobrien abort(); 14638494Sobrien} 14738494Sobrien 14838494Sobrien 14938494Sobrien/* 15038494Sobrien * Schedule a task to be run when woken up 15138494Sobrien */ 15238494Sobrienvoid 153174294Sobriensched_task(cb_fun *cf, opaque_t ca, wchan_t wchan) 15438494Sobrien{ 15538494Sobrien /* 15638494Sobrien * Allocate a new task 15738494Sobrien */ 15838494Sobrien pjob *p = sched_job(cf, ca); 15938494Sobrien 160174294Sobrien dlog("SLEEP on %p", wchan); 16138494Sobrien p->wchan = wchan; 16238494Sobrien p->pid = 0; 163174294Sobrien p->w = 0; /* was memset (when ->w was union) */ 16438494Sobrien} 16538494Sobrien 16638494Sobrien 16738494Sobrienstatic void 16838494Sobrienwakeupjob(pjob *p) 16938494Sobrien{ 17038494Sobrien rem_que(&p->hdr); 17138494Sobrien ins_que(&p->hdr, &proc_list_head); 17238494Sobrien task_notify_todo++; 17338494Sobrien} 17438494Sobrien 17538494Sobrien 17638494Sobrienvoid 177174294Sobrienwakeup(wchan_t wchan) 17838494Sobrien{ 17938494Sobrien pjob *p, *p2; 18038494Sobrien 18138494Sobrien if (!foreground) 18238494Sobrien return; 18338494Sobrien 18438494Sobrien /* 185174294Sobrien * Can't use ITER() here because 18638494Sobrien * wakeupjob() juggles the list. 18738494Sobrien */ 18838494Sobrien for (p = AM_FIRST(pjob, &proc_wait_list); 18938494Sobrien p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list); 19038494Sobrien p = p2) { 19138494Sobrien if (p->wchan == wchan) { 19238494Sobrien wakeupjob(p); 19338494Sobrien } 19438494Sobrien } 19538494Sobrien} 19638494Sobrien 19738494Sobrien 19838494Sobrienvoid 199174294Sobrienwakeup_task(int rc, int term, wchan_t wchan) 20038494Sobrien{ 201174294Sobrien wakeup(wchan); 20238494Sobrien} 20338494Sobrien 20438494Sobrien 205174294Sobrienwchan_t 206174294Sobrienget_mntfs_wchan(mntfs *mf) 207174294Sobrien{ 208174294Sobrien if (mf && 209174294Sobrien mf->mf_ops && 210174294Sobrien mf->mf_ops->get_wchan) 211174294Sobrien return mf->mf_ops->get_wchan(mf); 212174294Sobrien return mf; 213174294Sobrien} 214174294Sobrien 215174294Sobrien 21638494Sobrien/* 21738494Sobrien * Run any pending tasks. 21838494Sobrien * This must be called with SIGCHLD disabled 21938494Sobrien */ 22038494Sobrienvoid 22138494Sobriendo_task_notify(void) 22238494Sobrien{ 22338494Sobrien /* 22438494Sobrien * Keep taking the first item off the list and processing it. 22538494Sobrien * 22682794Sobrien * Done this way because the callback can, quite reasonably, 22738494Sobrien * queue a new task, so no local reference into the list can be 22838494Sobrien * held here. 22938494Sobrien */ 23038494Sobrien while (AM_FIRST(pjob, &proc_list_head) != HEAD(pjob, &proc_list_head)) { 23138494Sobrien pjob *p = AM_FIRST(pjob, &proc_list_head); 23238494Sobrien rem_que(&p->hdr); 23338494Sobrien /* 23438494Sobrien * This job has completed 23538494Sobrien */ 23638494Sobrien --task_notify_todo; 23738494Sobrien 23838494Sobrien /* 23938494Sobrien * Do callback if it exists 24038494Sobrien */ 24138494Sobrien if (p->cb_fun) { 24242629Sobrien /* these two trigraphs will ensure compatibility with strict POSIX.1 */ 243174294Sobrien p->cb_fun(WIFEXITED(p->w) ? WEXITSTATUS(p->w) : 0, 244174294Sobrien WIFSIGNALED(p->w) ? WTERMSIG(p->w) : 0, 245174294Sobrien p->cb_arg); 24638494Sobrien } 24738494Sobrien XFREE(p); 24838494Sobrien } 24938494Sobrien} 25038494Sobrien 25138494Sobrien 25238494SobrienRETSIGTYPE 25338494Sobriensigchld(int sig) 25438494Sobrien{ 25538494Sobrien int w; /* everyone these days uses int, not a "union wait" */ 25638494Sobrien int pid; 25738494Sobrien 25838494Sobrien#ifdef HAVE_WAITPID 25938494Sobrien while ((pid = waitpid((pid_t) -1, &w, WNOHANG)) > 0) { 26038494Sobrien#else /* not HAVE_WAITPID */ 261310490Scy while ((pid = wait3( &w, WNOHANG, (struct rusage *) NULL)) > 0) { 26238494Sobrien#endif /* not HAVE_WAITPID */ 26338494Sobrien pjob *p, *p2; 26438494Sobrien 26538494Sobrien if (WIFSIGNALED(w)) 26638494Sobrien plog(XLOG_ERROR, "Process %d exited with signal %d", 26738494Sobrien pid, WTERMSIG(w)); 26838494Sobrien else 26938494Sobrien dlog("Process %d exited with status %d", 27038494Sobrien pid, WEXITSTATUS(w)); 27138494Sobrien 27238494Sobrien for (p = AM_FIRST(pjob, &proc_wait_list); 27338494Sobrien p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list); 27438494Sobrien p = p2) { 27538494Sobrien if (p->pid == pid) { 27638494Sobrien p->w = w; 27738494Sobrien wakeupjob(p); 27838494Sobrien break; 27938494Sobrien } 28038494Sobrien } /* end of for loop */ 28138494Sobrien 282174294Sobrien if (p == HEAD(pjob, &proc_wait_list)) 28338494Sobrien dlog("can't locate task block for pid %d", pid); 28438494Sobrien 28538494Sobrien /* 28638494Sobrien * Must count down children inside the while loop, otherwise we won't 287174294Sobrien * count them all, and NumChildren (and later backoff) will be set 28838494Sobrien * incorrectly. SH/RUNIT 940519. 28938494Sobrien */ 290174294Sobrien if (--NumChildren < 0) 291174294Sobrien NumChildren = 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