1 /*
2 * Copyright (c) 1990 Jan-Simon Pendry
3 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Jan-Simon Pendry at Imperial College, London.
9 *
10 * %sccs.include.redist.c%
11 *
12 * @(#)sched.c 8.1 (Berkeley) 06/06/93
13 *
14 * $Id: sched.c,v 5.2.2.1 1992/02/09 15:09:02 jsp beta $
15 *
16 */
17
18 /*
19 * Process scheduler
20 */
21
22 #include "am.h"
23 #include <sys/signal.h>
24 #include WAIT
25 #include <setjmp.h>
26 extern jmp_buf select_intr;
27 extern int select_intr_valid;
28
29 typedef struct pjob pjob;
30 struct pjob {
31 qelem hdr; /* Linked list */
32 int pid; /* Process ID of job */
33 cb_fun cb_fun; /* Callback function */
34 voidp cb_closure; /* Closure for callback */
35 union wait w; /* Status filled in by sigchld */
36 voidp wchan; /* Wait channel */
37 };
38
39 extern qelem proc_list_head;
40 qelem proc_list_head = { &proc_list_head, &proc_list_head };
41 extern qelem proc_wait_list;
42 qelem proc_wait_list = { &proc_wait_list, &proc_wait_list };
43
44 int task_notify_todo;
45
ins_que(elem,pred)46 void ins_que(elem, pred)
47 qelem *elem, *pred;
48 {
49 qelem *p = pred->q_forw;
50 elem->q_back = pred;
51 elem->q_forw = p;
52 pred->q_forw = elem;
53 p->q_back = elem;
54 }
55
rem_que(elem)56 void rem_que(elem)
57 qelem *elem;
58 {
59 qelem *p = elem->q_forw;
60 qelem *p2 = elem->q_back;
61 p2->q_forw = p;
62 p->q_back = p2;
63 }
64
sched_job(cf,ca)65 static pjob *sched_job(cf, ca)
66 cb_fun cf;
67 voidp ca;
68 {
69 pjob *p = ALLOC(pjob);
70
71 p->cb_fun = cf;
72 p->cb_closure = ca;
73
74 /*
75 * Now place on wait queue
76 */
77 ins_que(&p->hdr, &proc_wait_list);
78
79 return p;
80 }
81
run_task(tf,ta,cf,ca)82 void run_task(tf, ta, cf, ca)
83 task_fun tf;
84 voidp ta;
85 cb_fun cf;
86 voidp ca;
87 {
88 pjob *p = sched_job(cf, ca);
89 int mask;
90
91 p->wchan = (voidp) p;
92
93 mask = sigblock(sigmask(SIGCHLD));
94
95 if (p->pid = background()) {
96 sigsetmask(mask);
97 return;
98 }
99
100 exit((*tf)(ta));
101 /* firewall... */
102 abort();
103 }
104
105 /*
106 * Schedule a task to be run when woken up
107 */
sched_task(cf,ca,wchan)108 void sched_task(cf, ca, wchan)
109 cb_fun cf;
110 voidp ca;
111 voidp wchan;
112 {
113 /*
114 * Allocate a new task
115 */
116 pjob *p = sched_job(cf, ca);
117 #ifdef DEBUG_SLEEP
118 dlog("SLEEP on %#x", wchan);
119 #endif
120 p->wchan = wchan;
121 p->pid = 0;
122 bzero((voidp) &p->w, sizeof(p->w));
123 }
124
wakeupjob(p)125 static void wakeupjob(p)
126 pjob *p;
127 {
128 rem_que(&p->hdr);
129 ins_que(&p->hdr, &proc_list_head);
130 task_notify_todo++;
131 }
132
wakeup(wchan)133 void wakeup(wchan)
134 voidp wchan;
135 {
136 pjob *p, *p2;
137 #ifdef DEBUG_SLEEP
138 int done = 0;
139 #endif
140 if (!foreground)
141 return;
142
143 #ifdef DEBUG_SLEEP
144 /*dlog("wakeup(%#x)", wchan);*/
145 #endif
146 /*
147 * Can't user ITER() here because
148 * wakeupjob() juggles the list.
149 */
150 for (p = FIRST(pjob, &proc_wait_list);
151 p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
152 p = p2) {
153 if (p->wchan == wchan) {
154 #ifdef DEBUG_SLEEP
155 done = 1;
156 #endif
157 wakeupjob(p);
158 }
159 }
160
161 #ifdef DEBUG_SLEEP
162 if (!done)
163 dlog("Nothing SLEEPing on %#x", wchan);
164 #endif
165 }
166
wakeup_task(rc,term,cl)167 void wakeup_task(rc, term, cl)
168 int rc;
169 int term;
170 voidp cl;
171 {
172 wakeup(cl);
173 }
174
175 /*ARGSUSED*/
176
sigchld(sig)177 void sigchld(sig)
178 int sig;
179 {
180 union wait w;
181 int pid;
182
183 #ifdef SYS5_SIGNALS
184 if ((pid = wait(&w)) > 0) {
185 #else
186 while ((pid = wait3((int *) &w, WNOHANG, (struct rusage *) 0)) > 0) {
187 #endif /* SYS5_SIGNALS */
188 pjob *p, *p2;
189
190 if (WIFSIGNALED(w))
191 plog(XLOG_ERROR, "Process %d exited with signal %d",
192 pid, w.w_termsig);
193 #ifdef DEBUG
194 else
195 dlog("Process %d exited with status %d",
196 pid, w.w_retcode);
197 #endif /* DEBUG */
198
199 for (p = FIRST(pjob, &proc_wait_list);
200 p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
201 p = p2) {
202 if (p->pid == pid) {
203 p->w = w;
204 wakeupjob(p);
205 break;
206 }
207 }
208
209 #ifdef DEBUG
210 if (p) ; else dlog("can't locate task block for pid %d", pid);
211 #endif /* DEBUG */
212 }
213
214 #ifdef SYS5_SIGNALS
215 signal(sig, sigchld);
216 #endif /* SYS5_SIGNALS */
217 if (select_intr_valid)
218 longjmp(select_intr, sig);
219 }
220
221 /*
222 * Run any pending tasks.
223 * This must be called with SIGCHLD disabled
224 */
do_task_notify(P_void)225 void do_task_notify(P_void)
226 {
227 /*
228 * Keep taking the first item off the list and processing it.
229 *
230 * Done this way because the 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 (FIRST(pjob, &proc_list_head) != HEAD(pjob, &proc_list_head)) {
235 pjob *p = 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 (*p->cb_fun)(p->w.w_retcode,
247 p->w.w_termsig, p->cb_closure);
248
249 free((voidp) p);
250 }
251 }
252
253 #ifdef HAS_SVR3_SIGNALS
254 /*
255 * 4.2 signal library based on svr3 (4.1+ bsd) interface
256 * From Stephen C. Pope <scp@acl.lanl.gov).
257 */
258
259 static int current_mask = 0;
260
sigblock(mask)261 int sigblock(mask)
262 int mask;
263 {
264 int sig;
265 int m;
266 int oldmask;
267
268 oldmask = current_mask;
269 for ( sig = 1, m = 1; sig <= MAXSIG; sig++, m <<= 1 ) {
270 if (mask & m) {
271 sighold(sig);
272 current_mask |= m;
273 }
274 }
275 return oldmask;
276 }
277
sigsetmask(mask)278 int sigsetmask(mask)
279 int mask;
280 {
281 int sig;
282 int m;
283 int oldmask;
284
285 oldmask = current_mask;
286 for ( sig = 1, m = 1; sig <= MAXSIG; sig++, m <<= 1 ) {
287 if (mask & m) {
288 sighold(sig);
289 current_mask |= m;
290 }
291 else {
292 sigrelse(sig);
293 current_mask &= ~m;
294 }
295 }
296 return oldmask;
297 }
298
299 #endif /* HAS_SVR3_SIGNALS */
300