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