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