home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume21 / amd / part04 / sched.c < prev   
C/C++ Source or Header  |  1990-04-10  |  5KB  |  250 lines

  1. /*
  2.  * $Id: sched.c,v 5.1.1.1 90/01/11 17:19:12 jsp Exp Locker: jsp $
  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.  * Redistribution and use in source and binary forms are permitted
  13.  * provided that the above copyright notice and this paragraph are
  14.  * duplicated in all such forms and that any documentation,
  15.  * advertising materials, and other materials related to such
  16.  * distribution and use acknowledge that the software was developed
  17.  * by Imperial College of Science, Technology and Medicine, London, UK.
  18.  * The names of the College and University may not be used to endorse
  19.  * or promote products derived from this software without specific
  20.  * prior written permission.
  21.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  22.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  23.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  24.  *
  25.  *    %W% (Berkeley) %G%
  26.  */
  27.  
  28. /*
  29.  * Process scheduler
  30.  */
  31.  
  32. #include "am.h"
  33. #include <sys/signal.h>
  34. #include WAIT
  35. #include <setjmp.h>
  36. extern jmp_buf select_intr;
  37. extern int select_intr_valid;
  38.  
  39. typedef struct pjob pjob;
  40. struct pjob {
  41.     qelem hdr;            /* Linked list */
  42.     int pid;            /* Process ID of job */
  43.     cb_fun cb_fun;            /* Callback function */
  44.     voidp cb_closure;        /* Closure for callback */
  45.     union wait w;            /* Status filled in by sigchld */
  46.     voidp wchan;            /* Wait channel */
  47. };
  48.  
  49. extern qelem proc_list_head;
  50. qelem proc_list_head = { &proc_list_head, &proc_list_head };
  51. extern qelem proc_wait_list;
  52. qelem proc_wait_list = { &proc_wait_list, &proc_wait_list };
  53.  
  54. int task_notify_todo;
  55.  
  56. void ins_que(elem, pred)
  57. qelem *elem, *pred;
  58. {
  59.     qelem *p = pred->q_forw;
  60.     elem->q_back = pred;
  61.     elem->q_forw = p;
  62.     pred->q_forw = elem;
  63.     p->q_back = elem;
  64. }
  65.  
  66. void rem_que(elem)
  67. qelem *elem;
  68. {
  69.     qelem *p = elem->q_forw;
  70.     qelem *p2 = elem->q_back;
  71.     p2->q_forw = p;
  72.     p->q_back = p2;
  73. }
  74.  
  75. static pjob *sched_job(cf, ca)
  76. cb_fun cf;
  77. voidp ca;
  78. {
  79.     pjob *p = ALLOC(pjob);
  80.  
  81.     p->cb_fun = cf;
  82.     p->cb_closure = ca;
  83.  
  84.     /*
  85.      * Now place on wait queue
  86.      */
  87.     ins_que(&p->hdr, &proc_wait_list);
  88.  
  89.     return p;
  90. }
  91.  
  92. void run_task(tf, ta, cf, ca)
  93. task_fun tf;
  94. voidp ta;
  95. cb_fun cf;
  96. voidp ca;
  97. {
  98.     pjob *p = sched_job(cf, ca);
  99.     int mask;
  100.  
  101.     p->wchan = (voidp) p;
  102.  
  103.     mask = sigblock(sigmask(SIGCHLD));
  104.  
  105.     if (p->pid = background()) {
  106.         sigsetmask(mask);
  107.         return;
  108.     }
  109.  
  110.     exit((*tf)(ta));
  111.     /* firewall... */
  112.     abort();
  113. }
  114.  
  115. /*
  116.  * Schedule a task to be run when woken up
  117.  */
  118. void sched_task(cf, ca, wchan)
  119. cb_fun cf;
  120. voidp ca;
  121. voidp wchan;
  122. {
  123.     /*
  124.      * Allocate a new task
  125.      */
  126.     pjob *p = sched_job(cf, ca);
  127. #ifdef DEBUG
  128.     /*dlog("sleep(%#x)", wchan);*/
  129. #endif
  130.     p->wchan = wchan;
  131.     p->pid = 0;
  132.     bzero((voidp) &p->w, sizeof(p->w));
  133. }
  134.  
  135. static void wakeupjob(p)
  136. pjob *p;
  137. {
  138.     rem_que(&p->hdr);
  139.     ins_que(&p->hdr, &proc_list_head);
  140.     task_notify_todo++;
  141. }
  142.  
  143. void wakeup(wchan)
  144. voidp wchan;
  145. {
  146.     pjob *p, *p2;
  147.  
  148.     if (!foreground)
  149.         return;
  150.  
  151. #ifdef DEBUG
  152.     /*dlog("wakeup(%#x)", wchan);*/
  153. #endif
  154.     /*
  155.      * Can't user ITER() here because
  156.      * wakeupjob() juggles the list.
  157.      */
  158.     for (p = FIRST(pjob, &proc_wait_list);
  159.             p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
  160.             p = p2) {
  161.         if (p->wchan == wchan)
  162.             wakeupjob(p);
  163.     }
  164. }
  165.  
  166. void wakeup_task(rc, term, cl)
  167. int rc;
  168. int term;
  169. voidp cl;
  170. {
  171.     wakeup(cl);
  172. }
  173.  
  174. /*ARGSUSED*/
  175. void sigchld(sig)
  176. int sig;
  177. {
  178.     union wait w;
  179.     int pid;
  180.  
  181. #ifdef SYS5_SIGNALS
  182.     if ((pid = wait(&w)) > 0) {
  183. #else
  184.     while ((pid = wait3(&w, WNOHANG, (union wait *) 0)) > 0) {
  185. #endif
  186.         pjob *p, *p2;
  187.  
  188.         if (WIFSIGNALED(w))
  189.             plog(XLOG_ERROR, "Process %d exited with signal %d",
  190.                 pid, w.w_termsig);
  191. #ifdef DEBUG
  192.         else
  193.             dlog("Process %d exited with status %d",
  194.                 pid, w.w_retcode);
  195. #endif
  196.  
  197.         for (p = FIRST(pjob, &proc_wait_list);
  198.                 p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list);
  199.                 p = p2) {
  200.             if (p->pid == pid) {
  201.                 p->w = w;
  202.                 wakeupjob(p);
  203.                 break;
  204.             }
  205.         }
  206.  
  207. #ifdef DEBUG
  208.         if (p) ; else dlog("can't locate task block for pid %d", pid);
  209. #endif
  210.     }
  211.  
  212. #ifdef SYS5_SIGNALS
  213.     signal(sig, sigchld);
  214. #endif
  215.     if (select_intr_valid)
  216.         longjmp(select_intr, sigchld);
  217. }
  218.  
  219. /*
  220.  * Run any pending tasks.
  221.  * This must be called with SIGCHLD disabled
  222.  */
  223. void task_notify(P_void)
  224. {
  225.     /*
  226.      * Keep taking the first item off the list and processing it.
  227.      *
  228.      * Done this way because the the callback can, quite reasonably,
  229.      * queue a new task, so no local reference into the list can be
  230.      * held here.
  231.      */
  232.     while (FIRST(pjob, &proc_list_head) != HEAD(pjob, &proc_list_head)) {
  233.         pjob *p = FIRST(pjob, &proc_list_head);
  234.         rem_que(&p->hdr);
  235.         /*
  236.          * This job has completed
  237.          */
  238.         --task_notify_todo;
  239.  
  240.         /*
  241.          * Do callback if it exists
  242.          */
  243.         if (p->cb_fun)
  244.             (*p->cb_fun)(p->w.w_retcode,
  245.                 p->w.w_termsig, p->cb_closure);
  246.  
  247.         free(p);
  248.     }
  249. }
  250.