1398a5aebSmckusick /*
2398a5aebSmckusick * Copyright (c) 1990 Jan-Simon Pendry
3398a5aebSmckusick * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
4*4092c5ccSbostic * Copyright (c) 1990, 1993
5*4092c5ccSbostic * The Regents of the University of California. All rights reserved.
6398a5aebSmckusick *
7398a5aebSmckusick * This code is derived from software contributed to Berkeley by
8398a5aebSmckusick * Jan-Simon Pendry at Imperial College, London.
9398a5aebSmckusick *
10398a5aebSmckusick * %sccs.include.redist.c%
11398a5aebSmckusick *
12*4092c5ccSbostic * @(#)sched.c 8.1 (Berkeley) 06/06/93
13c626267eSpendry *
14cc0207dcSpendry * $Id: sched.c,v 5.2.2.1 1992/02/09 15:09:02 jsp beta $
15c626267eSpendry *
16398a5aebSmckusick */
17398a5aebSmckusick
18398a5aebSmckusick /*
19398a5aebSmckusick * Process scheduler
20398a5aebSmckusick */
21398a5aebSmckusick
22398a5aebSmckusick #include "am.h"
23398a5aebSmckusick #include <sys/signal.h>
24398a5aebSmckusick #include WAIT
25398a5aebSmckusick #include <setjmp.h>
26398a5aebSmckusick extern jmp_buf select_intr;
27398a5aebSmckusick extern int select_intr_valid;
28398a5aebSmckusick
29398a5aebSmckusick typedef struct pjob pjob;
30398a5aebSmckusick struct pjob {
31398a5aebSmckusick qelem hdr; /* Linked list */
32398a5aebSmckusick int pid; /* Process ID of job */
33398a5aebSmckusick cb_fun cb_fun; /* Callback function */
34398a5aebSmckusick voidp cb_closure; /* Closure for callback */
35398a5aebSmckusick union wait w; /* Status filled in by sigchld */
36398a5aebSmckusick voidp wchan; /* Wait channel */
37398a5aebSmckusick };
38398a5aebSmckusick
39398a5aebSmckusick extern qelem proc_list_head;
40398a5aebSmckusick qelem proc_list_head = { &proc_list_head, &proc_list_head };
41398a5aebSmckusick extern qelem proc_wait_list;
42398a5aebSmckusick qelem proc_wait_list = { &proc_wait_list, &proc_wait_list };
43398a5aebSmckusick
44398a5aebSmckusick int task_notify_todo;
45398a5aebSmckusick
ins_que(elem,pred)46398a5aebSmckusick void ins_que(elem, pred)
47398a5aebSmckusick qelem *elem, *pred;
48398a5aebSmckusick {
49398a5aebSmckusick qelem *p = pred->q_forw;
50398a5aebSmckusick elem->q_back = pred;
51398a5aebSmckusick elem->q_forw = p;
52398a5aebSmckusick pred->q_forw = elem;
53398a5aebSmckusick p->q_back = elem;
54398a5aebSmckusick }
55398a5aebSmckusick
rem_que(elem)56398a5aebSmckusick void rem_que(elem)
57398a5aebSmckusick qelem *elem;
58398a5aebSmckusick {
59398a5aebSmckusick qelem *p = elem->q_forw;
60398a5aebSmckusick qelem *p2 = elem->q_back;
61398a5aebSmckusick p2->q_forw = p;
62398a5aebSmckusick p->q_back = p2;
63398a5aebSmckusick }
64398a5aebSmckusick
sched_job(cf,ca)65398a5aebSmckusick static pjob *sched_job(cf, ca)
66398a5aebSmckusick cb_fun cf;
67398a5aebSmckusick voidp ca;
68398a5aebSmckusick {
69398a5aebSmckusick pjob *p = ALLOC(pjob);
70398a5aebSmckusick
71398a5aebSmckusick p->cb_fun = cf;
72398a5aebSmckusick p->cb_closure = ca;
73398a5aebSmckusick
74398a5aebSmckusick /*
75398a5aebSmckusick * Now place on wait queue
76398a5aebSmckusick */
77398a5aebSmckusick ins_que(&p->hdr, &proc_wait_list);
78398a5aebSmckusick
79398a5aebSmckusick return p;
80398a5aebSmckusick }
81398a5aebSmckusick
run_task(tf,ta,cf,ca)82398a5aebSmckusick void run_task(tf, ta, cf, ca)
83398a5aebSmckusick task_fun tf;
84398a5aebSmckusick voidp ta;
85398a5aebSmckusick cb_fun cf;
86398a5aebSmckusick voidp ca;
87398a5aebSmckusick {
88398a5aebSmckusick pjob *p = sched_job(cf, ca);
89398a5aebSmckusick int mask;
90398a5aebSmckusick
91398a5aebSmckusick p->wchan = (voidp) p;
92398a5aebSmckusick
93398a5aebSmckusick mask = sigblock(sigmask(SIGCHLD));
94398a5aebSmckusick
95398a5aebSmckusick if (p->pid = background()) {
96398a5aebSmckusick sigsetmask(mask);
97398a5aebSmckusick return;
98398a5aebSmckusick }
99398a5aebSmckusick
100398a5aebSmckusick exit((*tf)(ta));
101398a5aebSmckusick /* firewall... */
102398a5aebSmckusick abort();
103398a5aebSmckusick }
104398a5aebSmckusick
105398a5aebSmckusick /*
106398a5aebSmckusick * Schedule a task to be run when woken up
107398a5aebSmckusick */
sched_task(cf,ca,wchan)108398a5aebSmckusick void sched_task(cf, ca, wchan)
109398a5aebSmckusick cb_fun cf;
110398a5aebSmckusick voidp ca;
111398a5aebSmckusick voidp wchan;
112398a5aebSmckusick {
113398a5aebSmckusick /*
114398a5aebSmckusick * Allocate a new task
115398a5aebSmckusick */
116398a5aebSmckusick pjob *p = sched_job(cf, ca);
117c626267eSpendry #ifdef DEBUG_SLEEP
118c626267eSpendry dlog("SLEEP on %#x", wchan);
119c626267eSpendry #endif
120398a5aebSmckusick p->wchan = wchan;
121398a5aebSmckusick p->pid = 0;
122398a5aebSmckusick bzero((voidp) &p->w, sizeof(p->w));
123398a5aebSmckusick }
124398a5aebSmckusick
wakeupjob(p)125398a5aebSmckusick static void wakeupjob(p)
126398a5aebSmckusick pjob *p;
127398a5aebSmckusick {
128398a5aebSmckusick rem_que(&p->hdr);
129398a5aebSmckusick ins_que(&p->hdr, &proc_list_head);
130398a5aebSmckusick task_notify_todo++;
131398a5aebSmckusick }
132398a5aebSmckusick
wakeup(wchan)133398a5aebSmckusick void wakeup(wchan)
134398a5aebSmckusick voidp wchan;
135398a5aebSmckusick {
136398a5aebSmckusick pjob *p, *p2;
137c626267eSpendry #ifdef DEBUG_SLEEP
138c626267eSpendry int done = 0;
139c626267eSpendry #endif
140398a5aebSmckusick if (!foreground)
141398a5aebSmckusick return;
142398a5aebSmckusick
143c626267eSpendry #ifdef DEBUG_SLEEP
144398a5aebSmckusick /*dlog("wakeup(%#x)", wchan);*/
145c626267eSpendry #endif
146398a5aebSmckusick /*
147398a5aebSmckusick * Can't user ITER() here because
148398a5aebSmckusick * wakeupjob() juggles the list.
149398a5aebSmckusick */
150398a5aebSmckusick for (p = FIRST(pjob, &proc_wait_list);
151398a5aebSmckusick p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
152398a5aebSmckusick p = p2) {
153c626267eSpendry if (p->wchan == wchan) {
154c626267eSpendry #ifdef DEBUG_SLEEP
155c626267eSpendry done = 1;
156c626267eSpendry #endif
157398a5aebSmckusick wakeupjob(p);
158398a5aebSmckusick }
159398a5aebSmckusick }
160398a5aebSmckusick
161c626267eSpendry #ifdef DEBUG_SLEEP
162c626267eSpendry if (!done)
163c626267eSpendry dlog("Nothing SLEEPing on %#x", wchan);
164c626267eSpendry #endif
165c626267eSpendry }
166c626267eSpendry
wakeup_task(rc,term,cl)167398a5aebSmckusick void wakeup_task(rc, term, cl)
168398a5aebSmckusick int rc;
169398a5aebSmckusick int term;
170398a5aebSmckusick voidp cl;
171398a5aebSmckusick {
172398a5aebSmckusick wakeup(cl);
173398a5aebSmckusick }
174398a5aebSmckusick
175398a5aebSmckusick /*ARGSUSED*/
176398a5aebSmckusick
sigchld(sig)177398a5aebSmckusick void sigchld(sig)
178398a5aebSmckusick int sig;
179398a5aebSmckusick {
180398a5aebSmckusick union wait w;
181398a5aebSmckusick int pid;
182398a5aebSmckusick
183398a5aebSmckusick #ifdef SYS5_SIGNALS
184398a5aebSmckusick if ((pid = wait(&w)) > 0) {
185398a5aebSmckusick #else
1868a89c22cSpendry while ((pid = wait3((int *) &w, WNOHANG, (struct rusage *) 0)) > 0) {
187398a5aebSmckusick #endif /* SYS5_SIGNALS */
188398a5aebSmckusick pjob *p, *p2;
189398a5aebSmckusick
190398a5aebSmckusick if (WIFSIGNALED(w))
191398a5aebSmckusick plog(XLOG_ERROR, "Process %d exited with signal %d",
192398a5aebSmckusick pid, w.w_termsig);
193398a5aebSmckusick #ifdef DEBUG
194398a5aebSmckusick else
195398a5aebSmckusick dlog("Process %d exited with status %d",
196398a5aebSmckusick pid, w.w_retcode);
197398a5aebSmckusick #endif /* DEBUG */
198398a5aebSmckusick
199398a5aebSmckusick for (p = FIRST(pjob, &proc_wait_list);
200398a5aebSmckusick p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
201398a5aebSmckusick p = p2) {
202398a5aebSmckusick if (p->pid == pid) {
203398a5aebSmckusick p->w = w;
204398a5aebSmckusick wakeupjob(p);
205398a5aebSmckusick break;
206398a5aebSmckusick }
207398a5aebSmckusick }
208398a5aebSmckusick
209398a5aebSmckusick #ifdef DEBUG
210398a5aebSmckusick if (p) ; else dlog("can't locate task block for pid %d", pid);
211398a5aebSmckusick #endif /* DEBUG */
212398a5aebSmckusick }
213398a5aebSmckusick
214398a5aebSmckusick #ifdef SYS5_SIGNALS
215398a5aebSmckusick signal(sig, sigchld);
216398a5aebSmckusick #endif /* SYS5_SIGNALS */
217398a5aebSmckusick if (select_intr_valid)
2188a89c22cSpendry longjmp(select_intr, sig);
219398a5aebSmckusick }
220398a5aebSmckusick
221398a5aebSmckusick /*
222398a5aebSmckusick * Run any pending tasks.
223398a5aebSmckusick * This must be called with SIGCHLD disabled
224398a5aebSmckusick */
do_task_notify(P_void)2258a89c22cSpendry void do_task_notify(P_void)
226398a5aebSmckusick {
227398a5aebSmckusick /*
228398a5aebSmckusick * Keep taking the first item off the list and processing it.
229398a5aebSmckusick *
230398a5aebSmckusick * Done this way because the the callback can, quite reasonably,
231398a5aebSmckusick * queue a new task, so no local reference into the list can be
232398a5aebSmckusick * held here.
233398a5aebSmckusick */
234398a5aebSmckusick while (FIRST(pjob, &proc_list_head) != HEAD(pjob, &proc_list_head)) {
235398a5aebSmckusick pjob *p = FIRST(pjob, &proc_list_head);
236398a5aebSmckusick rem_que(&p->hdr);
237398a5aebSmckusick /*
238398a5aebSmckusick * This job has completed
239398a5aebSmckusick */
240398a5aebSmckusick --task_notify_todo;
241398a5aebSmckusick
242398a5aebSmckusick /*
243398a5aebSmckusick * Do callback if it exists
244398a5aebSmckusick */
245398a5aebSmckusick if (p->cb_fun)
246398a5aebSmckusick (*p->cb_fun)(p->w.w_retcode,
247398a5aebSmckusick p->w.w_termsig, p->cb_closure);
248398a5aebSmckusick
2498a89c22cSpendry free((voidp) p);
250398a5aebSmckusick }
251398a5aebSmckusick }
252cc0207dcSpendry
253cc0207dcSpendry #ifdef HAS_SVR3_SIGNALS
254cc0207dcSpendry /*
255cc0207dcSpendry * 4.2 signal library based on svr3 (4.1+ bsd) interface
256cc0207dcSpendry * From Stephen C. Pope <scp@acl.lanl.gov).
257cc0207dcSpendry */
258cc0207dcSpendry
259cc0207dcSpendry static int current_mask = 0;
260cc0207dcSpendry
sigblock(mask)261cc0207dcSpendry int sigblock(mask)
262cc0207dcSpendry int mask;
263cc0207dcSpendry {
264cc0207dcSpendry int sig;
265cc0207dcSpendry int m;
266cc0207dcSpendry int oldmask;
267cc0207dcSpendry
268cc0207dcSpendry oldmask = current_mask;
269cc0207dcSpendry for ( sig = 1, m = 1; sig <= MAXSIG; sig++, m <<= 1 ) {
270cc0207dcSpendry if (mask & m) {
271cc0207dcSpendry sighold(sig);
272cc0207dcSpendry current_mask |= m;
273cc0207dcSpendry }
274cc0207dcSpendry }
275cc0207dcSpendry return oldmask;
276cc0207dcSpendry }
277cc0207dcSpendry
sigsetmask(mask)278cc0207dcSpendry int sigsetmask(mask)
279cc0207dcSpendry int mask;
280cc0207dcSpendry {
281cc0207dcSpendry int sig;
282cc0207dcSpendry int m;
283cc0207dcSpendry int oldmask;
284cc0207dcSpendry
285cc0207dcSpendry oldmask = current_mask;
286cc0207dcSpendry for ( sig = 1, m = 1; sig <= MAXSIG; sig++, m <<= 1 ) {
287cc0207dcSpendry if (mask & m) {
288cc0207dcSpendry sighold(sig);
289cc0207dcSpendry current_mask |= m;
290cc0207dcSpendry }
291cc0207dcSpendry else {
292cc0207dcSpendry sigrelse(sig);
293cc0207dcSpendry current_mask &= ~m;
294cc0207dcSpendry }
295cc0207dcSpendry }
296cc0207dcSpendry return oldmask;
297cc0207dcSpendry }
298cc0207dcSpendry
299cc0207dcSpendry #endif /* HAS_SVR3_SIGNALS */
300