xref: /netbsd-src/external/bsd/am-utils/dist/amd/sched.c (revision 8bae5d409deb915cf7c8f0539fae22ff2cb8a313)
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