MFC r1.27:
[dragonfly.git] / contrib / amd / amd / sched.c
blobe5cf6797696cb931c8dca127436b93abf672f353
1 /*
2 * Copyright (c) 1997-1999 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.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
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.
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.
39 * %W% (Berkeley) %G%
41 * $Id: sched.c,v 1.3 1999/01/13 23:31:01 ezk Exp $
46 * Process scheduler
49 #ifdef HAVE_CONFIG_H
50 # include <config.h>
51 #endif /* HAVE_CONFIG_H */
52 #include <am_defs.h>
53 #include <amd.h>
56 typedef struct pjob pjob;
58 struct pjob {
59 qelem hdr; /* Linked list */
60 int pid; /* Process ID of job */
61 cb_fun cb_fun; /* Callback function */
62 voidp cb_closure; /* Closure for callback */
63 int w; /* everyone these days uses int, not a "union wait" */
64 voidp wchan; /* Wait channel */
67 /* globals */
68 qelem proc_list_head = {&proc_list_head, &proc_list_head};
69 qelem proc_wait_list = {&proc_wait_list, &proc_wait_list};
70 int task_notify_todo;
73 void
74 ins_que(qelem *elem, qelem *pred)
76 qelem *p = pred->q_forw;
78 elem->q_back = pred;
79 elem->q_forw = p;
80 pred->q_forw = elem;
81 p->q_back = elem;
85 void
86 rem_que(qelem *elem)
88 qelem *p = elem->q_forw;
89 qelem *p2 = elem->q_back;
91 p2->q_forw = p;
92 p->q_back = p2;
96 static pjob *
97 sched_job(cb_fun cf, voidp ca)
99 pjob *p = ALLOC(struct pjob);
101 p->cb_fun = cf;
102 p->cb_closure = ca;
105 * Now place on wait queue
107 ins_que(&p->hdr, &proc_wait_list);
109 return p;
114 * tf: The task to execute (ta is its arguments)
115 * cf: Continuation function (ca is its arguments)
117 void
118 run_task(task_fun tf, voidp ta, cb_fun cf, voidp ca)
120 pjob *p = sched_job(cf, ca);
121 #ifdef HAVE_SIGACTION
122 sigset_t new, mask;
123 #else /* not HAVE_SIGACTION */
124 int mask;
125 #endif /* not HAVE_SIGACTION */
127 p->wchan = (voidp) p;
129 #ifdef HAVE_SIGACTION
130 sigemptyset(&new); /* initialize signal set we wish to block */
131 sigaddset(&new, SIGCHLD); /* only block on SIGCHLD */
132 sigprocmask(SIG_BLOCK, &new, &mask);
133 #else /* not HAVE_SIGACTION */
134 mask = sigblock(sigmask(SIGCHLD));
135 #endif /* not HAVE_SIGACTION */
137 if ((p->pid = background())) {
138 #ifdef HAVE_SIGACTION
139 sigprocmask(SIG_SETMASK, &mask, NULL);
140 #else /* not HAVE_SIGACTION */
141 sigsetmask(mask);
142 #endif /* not HAVE_SIGACTION */
143 return;
146 /* child code runs here, parent have returned to caller */
148 exit((*tf) (ta));
149 /* firewall... */
150 abort();
155 * Schedule a task to be run when woken up
157 void
158 sched_task(cb_fun cf, voidp ca, voidp wchan)
161 * Allocate a new task
163 pjob *p = sched_job(cf, ca);
165 #ifdef DEBUG
166 dlog("SLEEP on %#lx", (unsigned long) wchan);
167 #endif /* DEBUG */
168 p->wchan = wchan;
169 p->pid = 0;
170 memset((voidp) &p->w, 0, sizeof(p->w));
174 static void
175 wakeupjob(pjob *p)
177 rem_que(&p->hdr);
178 ins_que(&p->hdr, &proc_list_head);
179 task_notify_todo++;
183 void
184 wakeup(voidp wchan)
186 pjob *p, *p2;
188 if (!foreground)
189 return;
192 * Can't user ITER() here because
193 * wakeupjob() juggles the list.
195 for (p = AM_FIRST(pjob, &proc_wait_list);
196 p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
197 p = p2) {
198 if (p->wchan == wchan) {
199 wakeupjob(p);
205 void
206 wakeup_task(int rc, int term, voidp cl)
208 wakeup(cl);
213 * Run any pending tasks.
214 * This must be called with SIGCHLD disabled
216 void
217 do_task_notify(void)
220 * Keep taking the first item off the list and processing it.
222 * Done this way because the the callback can, quite reasonably,
223 * queue a new task, so no local reference into the list can be
224 * held here.
226 while (AM_FIRST(pjob, &proc_list_head) != HEAD(pjob, &proc_list_head)) {
227 pjob *p = AM_FIRST(pjob, &proc_list_head);
228 rem_que(&p->hdr);
230 * This job has completed
232 --task_notify_todo;
235 * Do callback if it exists
237 if (p->cb_fun) {
238 /* these two trigraphs will ensure compatibility with strict POSIX.1 */
239 (*p->cb_fun) (WIFEXITED(p->w) ? WEXITSTATUS(p->w) : 0,
240 WIFSIGNALED(p->w) ? WTERMSIG(p->w) : 0,
241 p->cb_closure);
243 XFREE(p);
248 RETSIGTYPE
249 sigchld(int sig)
251 int w; /* everyone these days uses int, not a "union wait" */
252 int pid;
254 #ifdef HAVE_WAITPID
255 while ((pid = waitpid((pid_t) -1, &w, WNOHANG)) > 0) {
256 #else /* not HAVE_WAITPID */
257 while ((pid = wait3( &w, WNOHANG, (struct rusage *) 0)) > 0) {
258 #endif /* not HAVE_WAITPID */
259 pjob *p, *p2;
261 if (WIFSIGNALED(w))
262 plog(XLOG_ERROR, "Process %d exited with signal %d",
263 pid, WTERMSIG(w));
264 #ifdef DEBUG
265 else
266 dlog("Process %d exited with status %d",
267 pid, WEXITSTATUS(w));
268 #endif /* DEBUG */
270 for (p = AM_FIRST(pjob, &proc_wait_list);
271 p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
272 p = p2) {
273 if (p->pid == pid) {
274 p->w = w;
275 wakeupjob(p);
276 break;
278 } /* end of for loop */
280 #ifdef DEBUG
281 if (!p)
282 dlog("can't locate task block for pid %d", pid);
283 #endif /* DEBUG */
286 * Must count down children inside the while loop, otherwise we won't
287 * count them all, and NumChild (and later backoff) will be set
288 * incorrectly. SH/RUNIT 940519.
290 if (--NumChild < 0)
291 NumChild = 0;
292 } /* end of "while wait..." loop */
294 #ifdef REINSTALL_SIGNAL_HANDLER
295 signal(sig, sigchld);
296 #endif /* REINSTALL_SIGNAL_HANDLER */
298 if (select_intr_valid)
299 longjmp(select_intr, sig);