xref: /original-bsd/usr.sbin/amd/amd/sched.c (revision 92ab646d)
1 /*
2  * $Id: sched.c,v 5.2 90/06/23 22:19:58 jsp Rel $
3  *
4  * Copyright (c) 1990 Jan-Simon Pendry
5  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
6  * Copyright (c) 1990 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * Jan-Simon Pendry at Imperial College, London.
11  *
12  * %sccs.include.redist.c%
13  *
14  *	@(#)sched.c	5.1 (Berkeley) 06/29/90
15  */
16 
17 /*
18  * Process scheduler
19  */
20 
21 #include "am.h"
22 #include <sys/signal.h>
23 #include WAIT
24 #include <setjmp.h>
25 extern jmp_buf select_intr;
26 extern int select_intr_valid;
27 
28 typedef struct pjob pjob;
29 struct pjob {
30 	qelem hdr;			/* Linked list */
31 	int pid;			/* Process ID of job */
32 	cb_fun cb_fun;			/* Callback function */
33 	voidp cb_closure;		/* Closure for callback */
34 	union wait w;			/* Status filled in by sigchld */
35 	voidp wchan;			/* Wait channel */
36 };
37 
38 extern qelem proc_list_head;
39 qelem proc_list_head = { &proc_list_head, &proc_list_head };
40 extern qelem proc_wait_list;
41 qelem proc_wait_list = { &proc_wait_list, &proc_wait_list };
42 
43 int task_notify_todo;
44 
45 void ins_que(elem, pred)
46 qelem *elem, *pred;
47 {
48 	qelem *p = pred->q_forw;
49 	elem->q_back = pred;
50 	elem->q_forw = p;
51 	pred->q_forw = elem;
52 	p->q_back = elem;
53 }
54 
55 void rem_que(elem)
56 qelem *elem;
57 {
58 	qelem *p = elem->q_forw;
59 	qelem *p2 = elem->q_back;
60 	p2->q_forw = p;
61 	p->q_back = p2;
62 }
63 
64 static pjob *sched_job(cf, ca)
65 cb_fun cf;
66 voidp ca;
67 {
68 	pjob *p = ALLOC(pjob);
69 
70 	p->cb_fun = cf;
71 	p->cb_closure = ca;
72 
73 	/*
74 	 * Now place on wait queue
75 	 */
76 	ins_que(&p->hdr, &proc_wait_list);
77 
78 	return p;
79 }
80 
81 void run_task(tf, ta, cf, ca)
82 task_fun tf;
83 voidp ta;
84 cb_fun cf;
85 voidp ca;
86 {
87 	pjob *p = sched_job(cf, ca);
88 	int mask;
89 
90 	p->wchan = (voidp) p;
91 
92 	mask = sigblock(sigmask(SIGCHLD));
93 
94 	if (p->pid = background()) {
95 		sigsetmask(mask);
96 		return;
97 	}
98 
99 	exit((*tf)(ta));
100 	/* firewall... */
101 	abort();
102 }
103 
104 /*
105  * Schedule a task to be run when woken up
106  */
107 void sched_task(cf, ca, wchan)
108 cb_fun cf;
109 voidp ca;
110 voidp wchan;
111 {
112 	/*
113 	 * Allocate a new task
114 	 */
115 	pjob *p = sched_job(cf, ca);
116 #ifdef DEBUG
117 	/*dlog("sleep(%#x)", wchan);*/
118 #endif /* DEBUG */
119 	p->wchan = wchan;
120 	p->pid = 0;
121 	bzero((voidp) &p->w, sizeof(p->w));
122 }
123 
124 static void wakeupjob(p)
125 pjob *p;
126 {
127 	rem_que(&p->hdr);
128 	ins_que(&p->hdr, &proc_list_head);
129 	task_notify_todo++;
130 }
131 
132 void wakeup(wchan)
133 voidp wchan;
134 {
135 	pjob *p, *p2;
136 
137 	if (!foreground)
138 		return;
139 
140 #ifdef DEBUG
141 	/*dlog("wakeup(%#x)", wchan);*/
142 #endif /* DEBUG */
143 	/*
144 	 * Can't user ITER() here because
145 	 * wakeupjob() juggles the list.
146 	 */
147 	for (p = FIRST(pjob, &proc_wait_list);
148 			p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
149 			p = p2) {
150 		if (p->wchan == wchan)
151 			wakeupjob(p);
152 	}
153 }
154 
155 void wakeup_task(rc, term, cl)
156 int rc;
157 int term;
158 voidp cl;
159 {
160 	wakeup(cl);
161 }
162 
163 /*ARGSUSED*/
164 
165 void sigchld(sig)
166 int sig;
167 {
168 	union wait w;
169 	int pid;
170 
171 #ifdef SYS5_SIGNALS
172 	if ((pid = wait(&w)) > 0) {
173 #else
174 	while ((pid = wait3(&w, WNOHANG, (union wait *) 0)) > 0) {
175 #endif /* SYS5_SIGNALS */
176 		pjob *p, *p2;
177 
178 		if (WIFSIGNALED(w))
179 			plog(XLOG_ERROR, "Process %d exited with signal %d",
180 				pid, w.w_termsig);
181 #ifdef DEBUG
182 		else
183 			dlog("Process %d exited with status %d",
184 				pid, w.w_retcode);
185 #endif /* DEBUG */
186 
187 		for (p = FIRST(pjob, &proc_wait_list);
188 				p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
189 				p = p2) {
190 			if (p->pid == pid) {
191 				p->w = w;
192 				wakeupjob(p);
193 				break;
194 			}
195 		}
196 
197 #ifdef DEBUG
198 		if (p) ; else dlog("can't locate task block for pid %d", pid);
199 #endif /* DEBUG */
200 	}
201 
202 #ifdef SYS5_SIGNALS
203 	signal(sig, sigchld);
204 #endif /* SYS5_SIGNALS */
205 	if (select_intr_valid)
206 		longjmp(select_intr, sigchld);
207 }
208 
209 /*
210  * Run any pending tasks.
211  * This must be called with SIGCHLD disabled
212  */
213 void task_notify(P_void)
214 {
215 	/*
216 	 * Keep taking the first item off the list and processing it.
217 	 *
218 	 * Done this way because the the callback can, quite reasonably,
219 	 * queue a new task, so no local reference into the list can be
220 	 * held here.
221 	 */
222 	while (FIRST(pjob, &proc_list_head) != HEAD(pjob, &proc_list_head)) {
223 		pjob *p = FIRST(pjob, &proc_list_head);
224 		rem_que(&p->hdr);
225 		/*
226 		 * This job has completed
227 		 */
228 		--task_notify_todo;
229 
230 		/*
231 		 * Do callback if it exists
232 		 */
233 		if (p->cb_fun)
234 			(*p->cb_fun)(p->w.w_retcode,
235 				p->w.w_termsig, p->cb_closure);
236 
237 		free(p);
238 	}
239 }
240