Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / bsd / am-utils / dist / amd / sched.c
blob068c95d1496e9ce083ad567b28101526de8cedd8
1 /* $NetBSD$ */
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.
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
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.
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.
42 * File: am-utils/amd/sched.c
47 * Process scheduler
50 #ifdef HAVE_CONFIG_H
51 # include <config.h>
52 #endif /* HAVE_CONFIG_H */
53 #include <am_defs.h>
54 #include <amd.h>
57 typedef struct pjob pjob;
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 */
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;
74 void
75 ins_que(qelem *elem, qelem *pred)
77 qelem *p = pred->q_forw;
79 elem->q_back = pred;
80 elem->q_forw = p;
81 pred->q_forw = elem;
82 p->q_back = elem;
86 void
87 rem_que(qelem *elem)
89 qelem *p = elem->q_forw;
90 qelem *p2 = elem->q_back;
92 p2->q_forw = p;
93 p->q_back = p2;
97 static pjob *
98 sched_job(cb_fun *cf, opaque_t ca)
100 pjob *p = ALLOC(struct pjob);
102 p->cb_fun = cf;
103 p->cb_arg = ca;
106 * Now place on wait queue
108 ins_que(&p->hdr, &proc_wait_list);
110 return p;
115 * tf: The task to execute (ta is its arguments)
116 * cf: Continuation function (ca is its arguments)
118 void
119 run_task(task_fun *tf, opaque_t ta, cb_fun *cf, opaque_t ca)
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 */
128 p->wchan = (wchan_t) p;
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 */
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;
147 /* child code runs here, parent has returned to caller */
149 exit((*tf) (ta));
150 /* firewall... */
151 abort();
156 * Schedule a task to be run when woken up
158 void
159 sched_task(cb_fun *cf, opaque_t ca, wchan_t wchan)
162 * Allocate a new task
164 pjob *p = sched_job(cf, ca);
166 dlog("SLEEP on %p", wchan);
167 p->wchan = wchan;
168 p->pid = 0;
169 p->w = 0; /* was memset (when ->w was union) */
173 static void
174 wakeupjob(pjob *p)
176 rem_que(&p->hdr);
177 ins_que(&p->hdr, &proc_list_head);
178 task_notify_todo++;
182 void
183 wakeup(wchan_t wchan)
185 pjob *p, *p2;
187 if (!foreground)
188 return;
191 * Can't use ITER() here because
192 * wakeupjob() juggles the list.
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);
204 void
205 wakeup_task(int rc, int term, wchan_t wchan)
207 wakeup(wchan);
211 wchan_t
212 get_mntfs_wchan(mntfs *mf)
214 if (mf &&
215 mf->mf_ops &&
216 mf->mf_ops->get_wchan)
217 return mf->mf_ops->get_wchan(mf);
218 return mf;
223 * Run any pending tasks.
224 * This must be called with SIGCHLD disabled
226 void
227 do_task_notify(void)
230 * Keep taking the first item off the list and processing it.
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.
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);
240 * This job has completed
242 --task_notify_todo;
245 * Do callback if it exists
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);
253 XFREE(p);
258 RETSIGTYPE
259 sigchld(int sig)
261 int w; /* everyone these days uses int, not a "union wait" */
262 int pid;
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;
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));
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;
286 } /* end of for loop */
288 if (p == HEAD(pjob, &proc_wait_list))
289 dlog("can't locate task block for pid %d", pid);
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.
296 if (--NumChildren < 0)
297 NumChildren = 0;
298 } /* end of "while wait..." loop */
300 #ifdef REINSTALL_SIGNAL_HANDLER
301 signal(sig, sigchld);
302 #endif /* REINSTALL_SIGNAL_HANDLER */
304 if (select_intr_valid)
305 longjmp(select_intr, sig);