]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/amd/amd/sched.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / amd / amd / sched.c
1 /*
2  * Copyright (c) 1997-2006 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  *
40  * File: am-utils/amd/sched.c
41  *
42  */
43
44 /*
45  * Process scheduler
46  */
47
48 #ifdef HAVE_CONFIG_H
49 # include <config.h>
50 #endif /* HAVE_CONFIG_H */
51 #include <am_defs.h>
52 #include <amd.h>
53
54
55 typedef struct pjob pjob;
56
57 struct pjob {
58   qelem hdr;            /* Linked list */
59   int pid;              /* Process ID of job */
60   cb_fun *cb_fun;       /* Callback function */
61   opaque_t cb_arg;      /* Argument for callback */
62   int w;                /* everyone these days uses int, not a "union wait" */
63   wchan_t wchan;        /* Wait channel */
64 };
65
66 /* globals */
67 qelem proc_list_head = {&proc_list_head, &proc_list_head};
68 qelem proc_wait_list = {&proc_wait_list, &proc_wait_list};
69 int task_notify_todo;
70
71
72 void
73 ins_que(qelem *elem, qelem *pred)
74 {
75   qelem *p = pred->q_forw;
76
77   elem->q_back = pred;
78   elem->q_forw = p;
79   pred->q_forw = elem;
80   p->q_back = elem;
81 }
82
83
84 void
85 rem_que(qelem *elem)
86 {
87   qelem *p = elem->q_forw;
88   qelem *p2 = elem->q_back;
89
90   p2->q_forw = p;
91   p->q_back = p2;
92 }
93
94
95 static pjob *
96 sched_job(cb_fun *cf, opaque_t ca)
97 {
98   pjob *p = ALLOC(struct pjob);
99
100   p->cb_fun = cf;
101   p->cb_arg = ca;
102
103   /*
104    * Now place on wait queue
105    */
106   ins_que(&p->hdr, &proc_wait_list);
107
108   return p;
109 }
110
111
112 /*
113  * tf: The task to execute (ta is its arguments)
114  * cf: Continuation function (ca is its arguments)
115  */
116 void
117 run_task(task_fun *tf, opaque_t ta, cb_fun *cf, opaque_t ca)
118 {
119   pjob *p = sched_job(cf, ca);
120 #ifdef HAVE_SIGACTION
121   sigset_t new, mask;
122 #else /* not HAVE_SIGACTION */
123   int mask;
124 #endif /* not HAVE_SIGACTION */
125
126   p->wchan = (wchan_t) p;
127
128 #ifdef HAVE_SIGACTION
129   sigemptyset(&new);            /* initialize signal set we wish to block */
130   sigaddset(&new, SIGCHLD);     /* only block on SIGCHLD */
131   sigprocmask(SIG_BLOCK, &new, &mask);
132 #else /* not HAVE_SIGACTION */
133   mask = sigblock(sigmask(SIGCHLD));
134 #endif /* not HAVE_SIGACTION */
135
136   if ((p->pid = background())) {
137 #ifdef HAVE_SIGACTION
138     sigprocmask(SIG_SETMASK, &mask, NULL);
139 #else /* not HAVE_SIGACTION */
140     sigsetmask(mask);
141 #endif /* not HAVE_SIGACTION */
142     return;
143   }
144
145   /* child code runs here, parent has returned to caller */
146
147   exit((*tf) (ta));
148   /* firewall... */
149   abort();
150 }
151
152
153 /*
154  * Schedule a task to be run when woken up
155  */
156 void
157 sched_task(cb_fun *cf, opaque_t ca, wchan_t wchan)
158 {
159   /*
160    * Allocate a new task
161    */
162   pjob *p = sched_job(cf, ca);
163
164   dlog("SLEEP on %p", wchan);
165   p->wchan = wchan;
166   p->pid = 0;
167   p->w = 0;                     /* was memset (when ->w was union) */
168 }
169
170
171 static void
172 wakeupjob(pjob *p)
173 {
174   rem_que(&p->hdr);
175   ins_que(&p->hdr, &proc_list_head);
176   task_notify_todo++;
177 }
178
179
180 void
181 wakeup(wchan_t wchan)
182 {
183   pjob *p, *p2;
184
185   if (!foreground)
186     return;
187
188   /*
189    * Can't use ITER() here because
190    * wakeupjob() juggles the list.
191    */
192   for (p = AM_FIRST(pjob, &proc_wait_list);
193        p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
194        p = p2) {
195     if (p->wchan == wchan) {
196       wakeupjob(p);
197     }
198   }
199 }
200
201
202 void
203 wakeup_task(int rc, int term, wchan_t wchan)
204 {
205   wakeup(wchan);
206 }
207
208
209 wchan_t
210 get_mntfs_wchan(mntfs *mf)
211 {
212   if (mf &&
213       mf->mf_ops &&
214       mf->mf_ops->get_wchan)
215     return mf->mf_ops->get_wchan(mf);
216   return mf;
217 }
218
219
220 /*
221  * Run any pending tasks.
222  * This must be called with SIGCHLD disabled
223  */
224 void
225 do_task_notify(void)
226 {
227   /*
228    * Keep taking the first item off the list and processing it.
229    *
230    * Done this way because the callback can, quite reasonably,
231    * queue a new task, so no local reference into the list can be
232    * held here.
233    */
234   while (AM_FIRST(pjob, &proc_list_head) != HEAD(pjob, &proc_list_head)) {
235     pjob *p = AM_FIRST(pjob, &proc_list_head);
236     rem_que(&p->hdr);
237     /*
238      * This job has completed
239      */
240     --task_notify_todo;
241
242     /*
243      * Do callback if it exists
244      */
245     if (p->cb_fun) {
246       /* these two trigraphs will ensure compatibility with strict POSIX.1 */
247       p->cb_fun(WIFEXITED(p->w)   ? WEXITSTATUS(p->w) : 0,
248                 WIFSIGNALED(p->w) ? WTERMSIG(p->w)    : 0,
249                 p->cb_arg);
250     }
251     XFREE(p);
252   }
253 }
254
255
256 RETSIGTYPE
257 sigchld(int sig)
258 {
259   int w;        /* everyone these days uses int, not a "union wait" */
260   int pid;
261
262 #ifdef HAVE_WAITPID
263   while ((pid = waitpid((pid_t) -1,  &w, WNOHANG)) > 0) {
264 #else /* not HAVE_WAITPID */
265   while ((pid = wait3( &w, WNOHANG, (struct rusage *) 0)) > 0) {
266 #endif /* not HAVE_WAITPID */
267     pjob *p, *p2;
268
269     if (WIFSIGNALED(w))
270       plog(XLOG_ERROR, "Process %d exited with signal %d",
271            pid, WTERMSIG(w));
272     else
273       dlog("Process %d exited with status %d",
274            pid, WEXITSTATUS(w));
275
276     for (p = AM_FIRST(pjob, &proc_wait_list);
277          p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
278          p = p2) {
279       if (p->pid == pid) {
280         p->w = w;
281         wakeupjob(p);
282         break;
283       }
284     } /* end of for loop */
285
286     if (p == HEAD(pjob, &proc_wait_list))
287       dlog("can't locate task block for pid %d", pid);
288
289     /*
290      * Must count down children inside the while loop, otherwise we won't
291      * count them all, and NumChildren (and later backoff) will be set
292      * incorrectly. SH/RUNIT 940519.
293      */
294     if (--NumChildren < 0)
295       NumChildren = 0;
296   } /* end of "while wait..." loop */
297
298 #ifdef REINSTALL_SIGNAL_HANDLER
299   signal(sig, sigchld);
300 #endif /* REINSTALL_SIGNAL_HANDLER */
301
302   if (select_intr_valid)
303     longjmp(select_intr, sig);
304 }