home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume21
/
amd
/
part04
/
sched.c
< prev
Wrap
C/C++ Source or Header
|
1990-04-10
|
5KB
|
250 lines
/*
* $Id: sched.c,v 5.1.1.1 90/01/11 17:19:12 jsp Exp Locker: jsp $
*
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Jan-Simon Pendry at Imperial College, London.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Imperial College of Science, Technology and Medicine, London, UK.
* The names of the College and University may not be used to endorse
* or promote products derived from this software without specific
* prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* %W% (Berkeley) %G%
*/
/*
* Process scheduler
*/
#include "am.h"
#include <sys/signal.h>
#include WAIT
#include <setjmp.h>
extern jmp_buf select_intr;
extern int select_intr_valid;
typedef struct pjob pjob;
struct pjob {
qelem hdr; /* Linked list */
int pid; /* Process ID of job */
cb_fun cb_fun; /* Callback function */
voidp cb_closure; /* Closure for callback */
union wait w; /* Status filled in by sigchld */
voidp wchan; /* Wait channel */
};
extern qelem proc_list_head;
qelem proc_list_head = { &proc_list_head, &proc_list_head };
extern qelem proc_wait_list;
qelem proc_wait_list = { &proc_wait_list, &proc_wait_list };
int task_notify_todo;
void ins_que(elem, pred)
qelem *elem, *pred;
{
qelem *p = pred->q_forw;
elem->q_back = pred;
elem->q_forw = p;
pred->q_forw = elem;
p->q_back = elem;
}
void rem_que(elem)
qelem *elem;
{
qelem *p = elem->q_forw;
qelem *p2 = elem->q_back;
p2->q_forw = p;
p->q_back = p2;
}
static pjob *sched_job(cf, ca)
cb_fun cf;
voidp ca;
{
pjob *p = ALLOC(pjob);
p->cb_fun = cf;
p->cb_closure = ca;
/*
* Now place on wait queue
*/
ins_que(&p->hdr, &proc_wait_list);
return p;
}
void run_task(tf, ta, cf, ca)
task_fun tf;
voidp ta;
cb_fun cf;
voidp ca;
{
pjob *p = sched_job(cf, ca);
int mask;
p->wchan = (voidp) p;
mask = sigblock(sigmask(SIGCHLD));
if (p->pid = background()) {
sigsetmask(mask);
return;
}
exit((*tf)(ta));
/* firewall... */
abort();
}
/*
* Schedule a task to be run when woken up
*/
void sched_task(cf, ca, wchan)
cb_fun cf;
voidp ca;
voidp wchan;
{
/*
* Allocate a new task
*/
pjob *p = sched_job(cf, ca);
#ifdef DEBUG
/*dlog("sleep(%#x)", wchan);*/
#endif
p->wchan = wchan;
p->pid = 0;
bzero((voidp) &p->w, sizeof(p->w));
}
static void wakeupjob(p)
pjob *p;
{
rem_que(&p->hdr);
ins_que(&p->hdr, &proc_list_head);
task_notify_todo++;
}
void wakeup(wchan)
voidp wchan;
{
pjob *p, *p2;
if (!foreground)
return;
#ifdef DEBUG
/*dlog("wakeup(%#x)", wchan);*/
#endif
/*
* Can't user ITER() here because
* wakeupjob() juggles the list.
*/
for (p = FIRST(pjob, &proc_wait_list);
p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
p = p2) {
if (p->wchan == wchan)
wakeupjob(p);
}
}
void wakeup_task(rc, term, cl)
int rc;
int term;
voidp cl;
{
wakeup(cl);
}
/*ARGSUSED*/
void sigchld(sig)
int sig;
{
union wait w;
int pid;
#ifdef SYS5_SIGNALS
if ((pid = wait(&w)) > 0) {
#else
while ((pid = wait3(&w, WNOHANG, (union wait *) 0)) > 0) {
#endif
pjob *p, *p2;
if (WIFSIGNALED(w))
plog(XLOG_ERROR, "Process %d exited with signal %d",
pid, w.w_termsig);
#ifdef DEBUG
else
dlog("Process %d exited with status %d",
pid, w.w_retcode);
#endif
for (p = FIRST(pjob, &proc_wait_list);
p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
p = p2) {
if (p->pid == pid) {
p->w = w;
wakeupjob(p);
break;
}
}
#ifdef DEBUG
if (p) ; else dlog("can't locate task block for pid %d", pid);
#endif
}
#ifdef SYS5_SIGNALS
signal(sig, sigchld);
#endif
if (select_intr_valid)
longjmp(select_intr, sigchld);
}
/*
* Run any pending tasks.
* This must be called with SIGCHLD disabled
*/
void task_notify(P_void)
{
/*
* Keep taking the first item off the list and processing it.
*
* Done this way because the the callback can, quite reasonably,
* queue a new task, so no local reference into the list can be
* held here.
*/
while (FIRST(pjob, &proc_list_head) != HEAD(pjob, &proc_list_head)) {
pjob *p = FIRST(pjob, &proc_list_head);
rem_que(&p->hdr);
/*
* This job has completed
*/
--task_notify_todo;
/*
* Do callback if it exists
*/
if (p->cb_fun)
(*p->cb_fun)(p->w.w_retcode,
p->w.w_termsig, p->cb_closure);
free(p);
}
}