xref: /original-bsd/usr.sbin/amd/amd/sched.c (revision c3e32dec)
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 
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 
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 
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 
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  */
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 
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 
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 
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 
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  */
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 
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 
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