Merge branch 'vendor/TCPDUMP'
[dragonfly.git] / contrib / amd / amd / sched.c
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.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Jan-Simon Pendry at Imperial College, London.
10  *
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.
26  *
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.
38  *
39  *      %W% (Berkeley) %G%
40  *
41  * $Id: sched.c,v 1.3 1999/01/13 23:31:01 ezk Exp $
42  *
43  */
44
45 /*
46  * Process scheduler
47  */
48
49 #ifdef HAVE_CONFIG_H
50 # include <config.h>
51 #endif /* HAVE_CONFIG_H */
52 #include <am_defs.h>
53 #include <amd.h>
54
55
56 typedef struct pjob pjob;
57
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 */
65 };
66
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;
71
72
73 void
74 ins_que(qelem *elem, qelem *pred)
75 {
76   qelem *p = pred->q_forw;
77
78   elem->q_back = pred;
79   elem->q_forw = p;
80   pred->q_forw = elem;
81   p->q_back = elem;
82 }
83
84
85 void
86 rem_que(qelem *elem)
87 {
88   qelem *p = elem->q_forw;
89   qelem *p2 = elem->q_back;
90
91   p2->q_forw = p;
92   p->q_back = p2;
93 }
94
95
96 static pjob *
97 sched_job(cb_fun cf, voidp ca)
98 {
99   pjob *p = ALLOC(struct pjob);
100
101   p->cb_fun = cf;
102   p->cb_closure = ca;
103
104   /*
105    * Now place on wait queue
106    */
107   ins_que(&p->hdr, &proc_wait_list);
108
109   return p;
110 }
111
112
113 /*
114  * tf: The task to execute (ta is its arguments)
115  * cf: Continuation function (ca is its arguments)
116  */
117 void
118 run_task(task_fun tf, voidp ta, cb_fun cf, voidp ca)
119 {
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 */
126
127   p->wchan = (voidp) p;
128
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 */
136
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;
144   }
145
146   /* child code runs here, parent have returned to caller */
147
148   exit((*tf) (ta));
149   /* firewall... */
150   abort();
151 }
152
153
154 /*
155  * Schedule a task to be run when woken up
156  */
157 void
158 sched_task(cb_fun cf, voidp ca, voidp wchan)
159 {
160   /*
161    * Allocate a new task
162    */
163   pjob *p = sched_job(cf, ca);
164
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));
171 }
172
173
174 static void
175 wakeupjob(pjob *p)
176 {
177   rem_que(&p->hdr);
178   ins_que(&p->hdr, &proc_list_head);
179   task_notify_todo++;
180 }
181
182
183 void
184 wakeup(voidp wchan)
185 {
186   pjob *p, *p2;
187
188   if (!foreground)
189     return;
190
191   /*
192    * Can't user ITER() here because
193    * wakeupjob() juggles the list.
194    */
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);
200     }
201   }
202 }
203
204
205 void
206 wakeup_task(int rc, int term, voidp cl)
207 {
208   wakeup(cl);
209 }
210
211
212 /*
213  * Run any pending tasks.
214  * This must be called with SIGCHLD disabled
215  */
216 void
217 do_task_notify(void)
218 {
219   /*
220    * Keep taking the first item off the list and processing it.
221    *
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.
225    */
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);
229     /*
230      * This job has completed
231      */
232     --task_notify_todo;
233
234     /*
235      * Do callback if it exists
236      */
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);
242     }
243     XFREE(p);
244   }
245 }
246
247
248 RETSIGTYPE
249 sigchld(int sig)
250 {
251   int w;        /* everyone these days uses int, not a "union wait" */
252   int pid;
253
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;
260
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 */
269
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;
277       }
278     } /* end of for loop */
279
280 #ifdef DEBUG
281     if (!p)
282       dlog("can't locate task block for pid %d", pid);
283 #endif /* DEBUG */
284
285     /*
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.
289      */
290     if (--NumChild < 0)
291       NumChild = 0;
292   } /* end of "while wait..." loop */
293
294 #ifdef REINSTALL_SIGNAL_HANDLER
295   signal(sig, sigchld);
296 #endif /* REINSTALL_SIGNAL_HANDLER */
297
298   if (select_intr_valid)
299     longjmp(select_intr, sig);
300 }