home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / ada / adaed-1.11 / adaed-1 / Adaed-1.11.0a / tasking.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-07  |  70.5 KB  |  2,265 lines

  1. /*
  2.  * Copyright (C) 1985-1992  New York University
  3.  * 
  4.  * This file is part of the Ada/Ed-C system.  See the Ada/Ed README file for
  5.  * warranty (none) and distribution info and also the GNU General Public
  6.  * License for more details.
  7.  
  8.  */
  9.  
  10. /*
  11.       +---------------------------------------------------+
  12.       |                                                   |
  13.       |          I N T E R P         T A S K I N G        |
  14.       |                                                   |
  15.       |                    (C Version)                    |
  16.       |                                                   |
  17.       |   Adapted From Low Level SETL version written by  |
  18.       |                                                   |
  19.       |                  Monte Zweben                     |
  20.       |               Philippe Kruchten                   |
  21.       |               Jean-Pierre Rosen                   |
  22.       |                                                   |
  23.       |    Original High Level SETL version written by    |
  24.       |                                                   |
  25.       |               Robert B. K. Dewar                  |
  26.       |                   Clint Goss                      |
  27.       |               Tracey M. Siesser                   |
  28.       |               Bernard D. Banner                   |
  29.       |               Stephen C. Bryant                   |
  30.       |                  Gerry Fisher                     |
  31.       |                                                   |
  32.       |              C version written by                 |
  33.       |                                                   |
  34.       |               Robert B. K. Dewar                  |
  35.       |                                                   |
  36.       +---------------------------------------------------+
  37. */
  38.  
  39.  
  40. /* Include standard header modules */
  41. #include <stdlib.h>
  42. #include <stdio.h>
  43. #include "config.h"
  44. #include "ipar.h"
  45. #include "ivars.h"
  46. #include "int.h"
  47. #include "tasking.h"
  48. #include "segment.h"
  49. #include "iparprots.h"
  50. #include "intaprots.h"
  51. #include "intbprots.h"
  52. #include "intcprots.h"
  53. #include "miscprots.h"
  54. #include "taskingprots.h"
  55.  
  56. #ifdef vms
  57. /*
  58. #include "adaexec.h"
  59. */
  60. #endif
  61.  
  62. #ifdef IBM_PC
  63. #include <time.h>
  64. static void sleep(unsigned);
  65. #endif
  66.  
  67. static void done_creation();
  68. static void create_task(int, int, struct rts_item *, int);
  69. static void done_activation();
  70. static void activate_self(int, int);
  71. static void kill(int);
  72. static void abortme();
  73. static void post_abort_one();
  74. static void post_complete_task_one();
  75. static void post_complete_block();
  76. static void post_complete_block_two();
  77. static void task_term();
  78. static void free_task_space();
  79. static void check_termination(int, int);
  80. static void check_done(int, int);
  81. static void check_unterm();
  82. static void tell_termination(int);
  83. static void uncreate_tasks(int);
  84. static void my_set_timer(struct io_item_type *, long);
  85. static int long my_reset_timer(long);
  86. static void wait(long, int);
  87. static void post_wait();
  88. static void catcher(long);
  89. static struct io_item_type *chain(int, long);
  90. static void check_free(struct io_item_type *);
  91. static int get_io(struct io_item_type *);
  92. static void disable_io(struct io_item_type **);
  93. static int remove_io(struct io_item_type **);
  94. static void schedule(int);
  95. static void finish_action(struct rts_item *);
  96. static void make_ready(int, int);
  97. static void transfer(int);
  98. static void evaluate_guards(int [], int);
  99. static void close_guards(int [], int);
  100. static void post_selective_wait(int, int, int [], int []);
  101. static void accept_rdv(int, int, int);
  102. static void post_entry_call();
  103. static void einit(struct entry_type    *);
  104. static int eremove(int);
  105. static void eput(struct entry_type *, int, struct q_item **);
  106. static int eget(struct entry_type *);
  107. static void add_lock(struct lock_type *);
  108. static void add_unlock(struct lock_type *);
  109. static void del_lock(struct lock_type *);
  110. static void del_unlock(struct lock_type *);
  111. static int entry_number(int, int, int);
  112. static void multisignal(int, int);
  113. static void add_serviced(int, int);
  114. static int remove_serviced();
  115. static void qinit();
  116. static void enqueue(int, int);
  117. static void enqueue_item(int, struct rts_item *);
  118. static struct rts_item *dequeue(struct ready_q *, int *);
  119. static void context_switch();
  120.  
  121. /* Global variables for tasking management */
  122.  
  123. /* id of the owner of the corr. stack */
  124. static int original_task[MAX_TASKS];
  125. /* Head of task chained waiting on clock */
  126. static struct io_item_type *clock_head;
  127. /* Highest priority of tasks to schedule */
  128. static int highest_priority;
  129. /* Previous value of time */
  130. static long last_time;
  131. /* temporary decl of ready queues  */
  132. static struct ready_q *ready_queue[MAX_PRIO];
  133.  
  134. /*-------------------------------------------------------------------------*
  135.  *                ----  T A S K I N G    S Y S T E M   ---                 *
  136.  *                                                                         *
  137.  *  The module contains all of the tasking control routines.  It is        *
  138.  *  divided into nine major sections.  Itemized under each section are the *
  139.  *  routines which are callable from outside the tasking module.  Unless   *
  140.  *  interface changes are made it is essential that the status of the      *
  141.  *  stack, on entry and exit from these routines, be maintained.           *
  142.  *                                                                         *
  143.  *      - Task Initialization                                              *
  144.  *      - Task Creation                                                    *
  145.  *               * start_creation                                          *
  146.  *      - Task Activation                                                  *
  147.  *               * start_activation                                        *
  148.  *               * end_activation                                          *
  149.  *      - Task Abortion                                                    *
  150.  *               * abort                                                   *
  151.  *      - Task Termination                                                 *
  152.  *               * complete_task                                           *
  153.  *               * complete_block                                          *
  154.  *               * terminate_unactivated                                   *
  155.  *               * purge_rdv                                               *
  156.  *      - Timer Maintainence                                               *
  157.  *               * delay_stmt                                              *
  158.  *      - Task Scheduler                                                   *
  159.  *      - Rendezvous                                                       *
  160.  *               * entry_call                                              *
  161.  *               * selectvie_wait                                          *
  162.  *               * end_rendezvous                                          *
  163.  *      - Utility Routines (queue routines etc.                            *
  164.  *               * raise_in_caller                                         *
  165.  *               * is_callable                                             *
  166.  *               * is_terminated                                           *
  167.  *               * count                                                   *
  168.  *                                                                         *
  169.  *-------------------------------------------------------------------------*/
  170.  
  171.  
  172. /*-------------------------------------------------------------------------*/
  173. /*            T A S K I N G    I N I T I A L I Z A T I O N                 */
  174. /*                                                                         */
  175. /*  Procedure to perform necessary initialization for tasking system       */
  176. /*-------------------------------------------------------------------------*/
  177.  
  178. void initialize_tasking()                            /*;initialize_tasking*/
  179. {
  180.     int     i;
  181.     int    *p;
  182.     long   itime();
  183.  
  184.     /*  Initialize variables */
  185.  
  186.     last_task = 1;
  187.  
  188.     for (i = 0; i < MAX_TASKS; i++) {
  189.         STACK(i) = (int *)0;
  190.         ORIG(i) = NULL_TASK;
  191.     }
  192.     qinit();
  193.     time_offset = 0;
  194.     last_time = itime();
  195.     clock_head = NULL;
  196.     next_clock = itime();
  197.     next_clock_flag = FALSE;
  198.  
  199.     /*  Initiate the idle task */
  200.  
  201.     p = STACK(0) = (int *) malloc((unsigned) sizeof(int) * main_task_size);
  202.     ORIG(0) = 0;
  203.     if (p == (int *)0) {
  204. #ifdef vms
  205.         LIB$STOP(MSG_NOSTACK);
  206. #else
  207.         printf("Unable to allocate stack\n");
  208.         exit(RC_ABORT);
  209. #endif
  210.     }
  211.  
  212.     TCB_ABNORMAL(0)      = 0;
  213.     TCB_ACTION(0)           = NO_ACTION;
  214.     TCB_BROTHER(0)         = 0;
  215.     TCB_BLOCK_PTR(0)     = (int *) 0;
  216.     TCB_CURR_ENTRY(0)     = NULL;
  217.     TCB_EVENT(0)         = NO_EVENT;
  218.     TCB_EXCEPTION(0)       = 0;
  219.     TCB_ENTRY_ITEM(0)     = 0;
  220.     TCB_FIRST(0)         = 0;
  221.     TCB_ID(0)             = 0;
  222.     TCB_IO_ITEM(0)         = NULL;
  223.     TCB_MASTER_TASK(0)     = NULL_TASK;
  224.     TCB_MASTER_BLOCK(0)     = 0;
  225.     TCB_NEXT(0)               = NULL_TASK;
  226.     TCB_NUM_ITEMS(0)       = 0;
  227.     TCB_NUM_NOTERM(0)       = 0;
  228.     TCB_NUM_DEPS(0)      = 0;
  229.     TCB_NUM_ENTRIES(0)   = 0;
  230.     TCB_NUM_EVENTS(0)       = 0;
  231.     TCB_PARENT(0)          = NULL_TASK;
  232.     TCB_PRIO(0)           = 0;
  233.     TCB_RDV(0)           = 0;
  234.     TCB_RTS_ITEM(0)         = NULL;
  235.     TCB_SAVE_PRIO(0)     = 0;
  236.     TCB_SERVICED(0)       = 0;
  237.     TCB_STATUS(0)           = ACTIVE;
  238.     TCB_TBASE(0)         = 1;
  239.     TCB_TOFF(0)             = 52;
  240.     TCB_WHAT(0)           = 0;
  241.     TCB_WHO(0)           = NULL_TASK;
  242.  
  243.     /*  Set context for idle task */
  244.  
  245.     STACKPTR(0) = WORDS_TCB;
  246.     tp = 0;
  247.     cur_stack = STACK(tp);
  248.     cur_stackptr = STACKPTR(tp);
  249.     bfp = 0;
  250.     ip = TASK_CODE_OFFSET;
  251.     cs = 1;
  252.     sfp = 0;
  253.     lin = 0;
  254.     exr = 0;
  255.     cur_code = code_segments[cs];
  256. }
  257.  
  258.  
  259. /*--------------------------------------------------------------------------*/
  260. /*                     T A S K    C R E A T I O N                           */
  261. /*                                                                          */
  262. /*  The following set of routines perform task creation                     */
  263. /*--------------------------------------------------------------------------*/
  264.  
  265. /*-------------------------------------------------------------------------*/
  266. /*                             START  CREATION                             */
  267. /*  Create an array of tasks, do so by creating a RTS item for the array   */
  268. /*  As tasks become ready to run they will perform activations etc. first  */
  269. /*  using this RTS item                                                    */
  270. /*-------------------------------------------------------------------------*/
  271.  
  272. void start_creation(int templ_base, int templ_off)            /*;start_creation*/
  273. {
  274.     int    mult = 1;
  275.     struct rts_item     *rts;
  276.  
  277.     if (BLOCK_FRAME->bf_tasks_declared == NULL)
  278.         push_task_frame(NULL_TASK);        /* create null frame */
  279.  
  280.     rts = (struct rts_item *) malloc(sizeof(struct rts_item));
  281.     if (rts == (struct rts_item *)0) {
  282.         raise(STORAGE_ERROR, "Allocating space for task");
  283.         return;
  284.     }
  285.     rts->tcbs = (int *) malloc((unsigned) sizeof(int)*mult);
  286.     if (rts->tcbs == (int *)0) {
  287.         raise(STORAGE_ERROR, "Allocating space for task");
  288.         return;
  289.     }
  290.     RTS_TYPE(rts) = CREATE;
  291.     RTS_PRIO(rts) = MY_PRIO;
  292.     RTS_TEMPL_BASE(rts) = templ_base;
  293.     RTS_TEMPL_OFF(rts) = templ_off;
  294.     RTS_MULT(rts) = mult;
  295.     RTS_NEXT(rts) = NULL;
  296.     RTS_PARENT(rts) = tp;
  297.  
  298.     MY_WHAT = NULL_TASK;
  299.     MY_NUM_ITEMS = mult;
  300.     enqueue_item(MY_PRIO, rts);
  301.     schedule(DONE_CREATION);
  302. }
  303.  
  304. /*--------------------------------------------------------------------------*/
  305. /*                             DONE   CREATION                              */
  306. /*   Performed after all of my tasks have finished creation.  Add current   */
  307. /*   RTS item to chain                                                      */
  308. /*--------------------------------------------------------------------------*/
  309.  
  310. static void done_creation()                                    /*;done_creation*/
  311. {
  312.     if (MY_EXCEPTION == STORAGE_ERROR) {
  313.         raise(STORAGE_ERROR, "Not enough space for new tasks");
  314.         MY_EXCEPTION = 0;
  315.     }
  316.     if (MY_WHAT != NULL_TASK)         /* MY_WHAT is leader of RTS */
  317.         TCB_BROTHER(MY_WHAT) = FAS(MY_TASKS_DECLARED, MY_WHAT);
  318.     PUSH(MY_WHAT); /* Must add item to chain of rts items */
  319. }
  320.  
  321. /*-----------------------------------------------------------------------*/
  322. /*                            CREATE  TASK                               */
  323. /*  Procedure to create task and put it on parents frame chain           */
  324. /*-----------------------------------------------------------------------*/
  325.  
  326. static void create_task(int templ_base, int templ_off, struct rts_item *rts,
  327.   int my_id)                                                    /*;create_task*/
  328. {
  329.     int     task_nr, parent;    /* nr of the task to be created */
  330.     int     i, *p, old_last_task;    /* temporary variable */
  331.  
  332.     /* STEP 1: Search the stack_segments for a stack */
  333.  
  334.     old_last_task = last_task;
  335.     task_nr = INC(last_task);
  336.     parent = RTS_PARENT(rts);
  337.     for(;task_nr < old_last_task + MAX_TASKS; task_nr = INC(last_task))
  338.         if (ORIG(task_nr) == NULL_TASK) break;
  339.     if (task_nr >= old_last_task + MAX_TASKS) {/* Error if no avail stack */
  340.         FAS(&(TCB_EXCEPTION(parent)),PROGRAM_ERROR);
  341.         multisignal(parent, NO_EVENT);
  342.         return;
  343.     }
  344.  
  345.     /* STEP 2: Create task frame for new task */
  346.  
  347.     p=STACK(task_nr) = (int *) malloc((unsigned) sizeof(int)*new_task_size);
  348.     ORIG(task_nr) = task_nr;
  349.  
  350.     /* STEP 3 : Create storage area for task and initialize */
  351.     if (p == (int *)0) {
  352.         RTS_TCBS(rts, my_id) = NULL_TASK;
  353.         DEC(RTS_MULT(rts));
  354.         FAS(&(TCB_EXCEPTION(parent)), STORAGE_ERROR);
  355.         STACKPTR(task_nr) = 0;
  356.         multisignal(parent, NO_EVENT);
  357.     }
  358.     else {
  359.         TCB_ABNORMAL(task_nr)       = 0;
  360.         TCB_ACTION(task_nr)       = ACTIVATE_SELF;
  361.         TCB_BLOCK_PTR(task_nr)       = (int *) 0;
  362.         TCB_BROTHER(task_nr)       = NULL_BROTHER;
  363.         TCB_CURR_ENTRY(task_nr)   = NULL;
  364.         TCB_ENTRY_ITEM(task_nr)   = NULL;
  365.         TCB_EVENT(task_nr)           = NO_EVENT;
  366.         TCB_EXCEPTION(task_nr)    = 0;
  367.         TCB_FIRST(task_nr)          = 0;
  368.         TCB_ID(task_nr)              = my_id;
  369.         TCB_IO_ITEM(task_nr)       = NULL;
  370.         TCB_MASTER_BLOCK(task_nr) = 0;
  371.         TCB_MASTER_TASK(task_nr)  = NULL_TASK;
  372.         TCB_NEXT(task_nr)           = NULL_TASK;
  373.         TCB_NUM_ITEMS(task_nr)       = 0;
  374.         TCB_NUM_DEPS(task_nr)       = 0;
  375.         TCB_NUM_ENTRIES(task_nr)  =
  376.           TASK(ADDR(templ_base,templ_off))->nb_entries;
  377.         TCB_NUM_EVENTS(task_nr)   = 0;
  378.         TCB_NUM_NOTERM(task_nr)   = 0;
  379.         TCB_PARENT(task_nr)       = RTS_PARENT(rts);
  380.         TCB_PRIO(task_nr)         = TASK(ADDR(templ_base, templ_off))->priority;
  381.         TCB_RDV(task_nr)            = 0;
  382.         TCB_RTS_ITEM(task_nr)     = rts;
  383.         TCB_SAVE_PRIO(task_nr)      = 0;
  384.         TCB_SERVICED(task_nr)       = NULL_TASK;
  385.         TCB_STATUS(task_nr)       = ACTIVATING;
  386.         TCB_TBASE(task_nr)           = templ_base;
  387.         TCB_TOFF(task_nr)           = templ_off + WORDS_TASK;
  388.         TCB_WHAT(task_nr)           = 0;
  389.         TCB_WHO(task_nr)           = NULL_TASK;
  390.  
  391.         /* add space for queue headers */
  392.  
  393.         for (i=1; i<=TASK(ADDR(templ_base,templ_off))->nb_entries; i++)
  394.             einit(TCB_ENTRY(task_nr, i));
  395.         p = (int *)(TCB_ENTRY(task_nr, i));
  396.  
  397.         *p++ = 0;        /* EXR */
  398.         *p++ = 0;        /* LIN */
  399.         *p++ = 0;        /* SFP */
  400.         *p++ = 0;        /* CS */
  401.         *p++ = 0;        /* IP */
  402.         STACKPTR(task_nr) = p - STACK(task_nr);
  403.         *p++ = 0;        /* BFP */
  404. #ifdef TRACE
  405.         if(tasking_trace)
  406.             printf("task %d creating task %d\n",tp,task_nr);
  407. #endif
  408.         RTS_TCBS(TCB_RTS_ITEM(task_nr), TCB_ID(task_nr)) = task_nr;
  409.         TCB_WHAT(TCB_PARENT(task_nr)) = task_nr;
  410.         multisignal(RTS_PARENT(TCB_RTS_ITEM(task_nr)), NO_EVENT);
  411.     }
  412. }
  413.  
  414. /*--------------------------------------------------------------------------*
  415.  *                     T A S K    A C T I V A T I O N                       *
  416.  *                                                                          *
  417.  *  The following set of routines perform task activation                   *
  418.  *--------------------------------------------------------------------------*/
  419.  
  420.  
  421. /*--------------------------------------------------------------------------*
  422.  *                         START  ACTIVATION                                *
  423.  *  This routines is used by a task to preprocess it's task list in order   *
  424.  *  to find out how many tasks must be activated.  It then adds the items   *
  425.  *  in the tasks list to the ready queue in order that they may then be     *
  426.  *  activated in parallel.  When they are done being activated, the parent  *
  427.  *  task may continue processing.                                           *
  428.  *--------------------------------------------------------------------------*/
  429.  
  430. void start_activation(int task_list, int task_master, int task_block)
  431.                                                         /*;start_activation*/
  432. {
  433.     int    i, task, next_task, num_tasks;
  434.     struct rts_item    *item;
  435.  
  436.     if (MY_ABNORMAL) {
  437.         uncreate_tasks(task_list);
  438.         abortme();
  439.         return;
  440.     }
  441.  
  442.     task = task_list;
  443.     num_tasks = 0;
  444.     while (task != NULL_TASK) {
  445.         num_tasks += RTS_MULT(TCB_RTS_ITEM(task));
  446.         task = TCB_BROTHER(task);
  447.     }
  448.     MY_NUM_ITEMS = num_tasks;
  449.     MY_EVENT = NO_EVENT;
  450.  
  451.     if (TCB_ABNORMAL(task_master)) return;
  452.  
  453.     MY_STATUS = ACTIVATING;
  454.     task = task_list;
  455.     for (i=0;i<num_tasks;i++) {
  456.         next_task = TCB_BROTHER(task);
  457.         item = TCB_RTS_ITEM(task);
  458.         RTS_MASTER_TASK(item) = task_master;
  459.         RTS_MASTER_BLOCK(item) = task_block;
  460.         RTS_PRIO(item) = MY_PRIO;
  461.         RTS_TYPE(item) = ACTIVATE;
  462.         RTS_NEXT(item) = NULL;
  463.         enqueue_item(MY_PRIO, item);
  464.         task = next_task;
  465.     }
  466.     schedule(DONE_ACTIVATION);
  467. }
  468.  
  469. /*--------------------------------------------------------------------------*/
  470. /*                         DONE   ACTIVATION                                */
  471. /*  This routines is called by the parent task when all of its tasks have   */
  472. /*  finished their activation.  It checks that it is ok, if not it aborts   */
  473. /*  all of the children.                                                    */
  474. /*--------------------------------------------------------------------------*/
  475.  
  476. static void done_activation()                             /*;done_activation*/
  477. {
  478.     if (MY_ABNORMAL) {
  479.         abortme();
  480.         return;
  481.     }
  482.     if (MY_EVENT == TASKERR_EVENT) {
  483.         raise(TASKING_ERROR, "Tasking error in activation");
  484.         MY_EXCEPTION = 0;
  485.     }
  486.     else if (MY_EVENT == PROGERR_EVENT) {
  487.         raise(PROGRAM_ERROR, "Activating an unelaborated task");
  488.         MY_EXCEPTION = 0;
  489.     }
  490.     MY_ACTION = NO_ACTION;
  491. }
  492.  
  493. int union_tasks_declared(int list1, int list2)        /*;union_tasks_declared */
  494. {
  495.     int    head2, tail1;
  496.  
  497.     if (list1 == NULL_TASK) return list2;
  498.     if (list2 == NULL_TASK) return list1;
  499.  
  500.     tail1 = list1;
  501.     while (TCB_BROTHER(tail1) != NULL_TASK) tail1 = TCB_BROTHER(tail1);
  502.  
  503.     head2 = FAS(&(list2), list1);
  504.     FAS(&(TCB_BROTHER(tail1)), head2);
  505.     return list1;
  506. }
  507.  
  508. /*------------------------------------------------------------------------*/
  509. /*                  TASK  ACTIVATION                                         */
  510. /* Procedure to activate self and put on the bf_subtasks chain if leader  */
  511. /*------------------------------------------------------------------------*/
  512.  
  513. static void activate_self(int task_master, int task_bfp)     /*;activate_self*/
  514. {
  515.     int    *ptr;                  /* memory address */
  516.     int     i, val1, val2, tmp_base, tmp_off; /* temporary base */
  517.  
  518.     if (MY_BROTHER != NULL_BROTHER)     /* I am leader of RTS */
  519.         MY_BROTHER =
  520.           FAS(&(((struct bf *)(STACK(task_master)+task_bfp))->bf_subtasks), tp);
  521.  
  522.     if (MY_STATUS == TERMINATED || MY_ABNORMAL) { /* may have been aborted */
  523.         MY_STATUS = TERMINATED;
  524.         multisignal(MY_PARENT, NO_EVENT);
  525.         schedule(NO_ACTION);
  526.         return;
  527.     }
  528.  
  529.     MY_MASTER_TASK = task_master;
  530.     MY_MASTER_BLOCK= task_bfp;
  531.     MY_NUM_NOTERM = 1;         /* myself */
  532.     MY_NUM_DEPS = 1;         /* myself */
  533.  
  534.     ptr = ADDR(MY_TBASE, MY_TOFF-WORDS_TASK);
  535.     tmp_base = TASK(ptr)->body_base;
  536.     tmp_off = TASK(ptr)->body_off;
  537.     ptr = ADDR(tmp_base, tmp_off);
  538.     cs = *ptr;
  539.     if (cs < 1) {    /* Not elaborated !! TBSL */
  540.         TCB_EXCEPTION(MY_PARENT) = PROGRAM_ERROR;
  541.         multisignal(MY_PARENT, PROGERR_EVENT);
  542.         schedule(NO_ACTION);
  543.         return;
  544.     }
  545.     ip = TASK_CODE_OFFSET;
  546.  
  547.     /* reserve space for local variables */
  548.     /* note: this could be somehow optimized by just moving */
  549.     /*   the Top of Stack.... */
  550.  
  551. #ifdef ALIGN_WORD
  552.     val1 = get_int((int *)(code_segments[cs] + code_seglen[cs] - sizeof(int)
  553.       -1));
  554. #else
  555.     val1 = *(int *)(code_segments[cs] + code_seglen[cs] - sizeof(int) - 1);
  556. #endif
  557.     for (i = 0; i < val1; i++)
  558.         PUSH(0);
  559.  
  560.     i = cur_stackptr + NB_REGISTERS - 1;
  561.     PUSH(i);        /* SFP -- this is a trap */
  562.     PUSH(cs);        /* CS */
  563.     PUSH(lin);      /* LIN*/
  564.     PUSH(ip);        /* IP */
  565.     sfp = cur_stackptr + 1;
  566.     /* copy relay set */
  567.  
  568.     val2 = *++ptr * 2;    /* length */
  569.     for (i = 0; i < val2; i++)
  570.         PUSH(*++ptr);
  571.  
  572.     /* Dummy block frame for trapping exceptions */
  573.     PUSH(0);        /* bfp */
  574.     bfp = cur_stackptr;
  575.     PUSHP(0L);        /* data_link */
  576.     PUSHP(0L);        /* tasks_declared */
  577.     PUSH(1);        /* num_noterm */
  578.     PUSH(1);        /* num_deps */
  579.     PUSH(NULL_TASK);/* subtasks */
  580.     PUSH(2);        /* exception vector */
  581.     cur_code = code_segments[cs];
  582.  
  583.     /* This must occur after possible to detect all errors */
  584.  
  585.     INC(TCB_NUM_NOTERM(MY_MASTER_TASK));
  586.     INC(TCB_NUM_DEPS(MY_MASTER_TASK));
  587.     INC(BF_NUM_NOTERM(MY_MASTER_TASK, MY_MASTER_BLOCK));
  588.     INC(BF_NUM_DEPS(MY_MASTER_TASK, MY_MASTER_BLOCK));
  589.  
  590. #ifdef TRACE
  591.     if (tasking_trace) {
  592.         printf("task %d activating task %d\n",task_master,tp);
  593.     }
  594. #endif
  595. }
  596.  
  597.  
  598. /*-------------------------------------------------------------------------*/
  599. /*                            END  ACTIVATION                              */
  600. /* Procedure called at the end of activation to signal the parent task     */
  601. /* that everything is OK (or not as the case may be)                       */
  602. /*-------------------------------------------------------------------------*/
  603.  
  604. void end_activation(int term_code)                 /*;end_activation*/
  605. {
  606.     /* after we passed the end of activation, the exception vector */
  607.     /* of the very first block shall designate the task_trap. */
  608.  
  609.     BF_HANDLER(tp, MY_PREVIOUS_BFP) = 2;
  610.     if (term_code == 0) {
  611.         TCB_EXCEPTION(MY_PARENT) = TASKING_ERROR;
  612.         DEC(RTS_MULT(MY_RTS_ITEM));
  613.         RTS_TCBS(MY_RTS_ITEM, MY_ID) = NULL_TASK;
  614.         multisignal(MY_PARENT, TASKERR_EVENT);
  615.     }
  616.     else {
  617.         MY_STATUS = ACTIVE;
  618.         multisignal(MY_PARENT, NO_EVENT);
  619.     }
  620. }
  621.  
  622. /*--------------------------------------------------------------------------*/
  623. /*                  A B O R T    R O U T I N E S                            */
  624. /*--------------------------------------------------------------------------*/
  625.  
  626. /*--------------------------------------------------------------------------*/
  627. /*                                 ABORT                                    */
  628. /* Procedure used to abort nr_task tasks whose numbers are on the stack     */
  629. /*--------------------------------------------------------------------------*/
  630.  
  631. void abort(int nr_tasks)                                         /*;abort*/
  632. {
  633.     int     current;    /* pointer to the task currently aborting */
  634.     int     i;        /* temporary loop index */
  635.  
  636.     for (i = 0; i < nr_tasks; i++) {
  637.         POP(current);
  638.         kill(current);
  639.     }
  640.     if (MY_ABNORMAL)   /* Suicide! */
  641.         abortme();
  642. }
  643.  
  644. /*--------------------------------------------------------------------------*/
  645. /*                       KILL                                                */
  646. /* Procedure to abort task, after having aborted its dependent tasks. If    */
  647. /* nobody in the family is engaged in a rendezvous, then the task is made   */
  648. /* terminated and space of dependent tasks is released. This procedure does */
  649. /* not call WAIT: this has to be done by the caller if it aborts itself.    */
  650. /*--------------------------------------------------------------------------*/
  651.  
  652. static void kill(int task)                                            /*;kill*/
  653. {
  654.     int      task2, dep, i, j, block;
  655.  
  656.     /* STEP 1: Check status etc. of task being aborted ...  */
  657.  
  658.     if (INC(TCB_ABNORMAL(task)) || (TCB_STATUS(task) == TERMINATED)) {
  659.         /* more than one task trying to abort it, must clean up ... */
  660. #ifdef TRACE
  661.         if (tasking_trace)
  662.             printf("task %d aborting terminated task %d\n",tp,task);
  663. #endif
  664.         DEC(TCB_ABNORMAL(task));        /* avoid overflow */
  665.         return;
  666.     }
  667.  
  668. #ifdef TRACE
  669.     if (tasking_trace && TCB_ABNORMAL(task))
  670.         printf("task %d aborting task %d\n",tp,task);
  671. #endif
  672.  
  673.     /* STEP 2:  Kill all dependent tasks by block
  674.      *        I can spawn tasks and use a multi-wait count here to make sure done
  675.      */
  676.     if (TCB_BLOCK_PTR(task) == NULL) block = 0;  /* no yet activated ... */
  677.     else block = *(TCB_BLOCK_PTR(task));
  678.     while (block != 0) {
  679.         task2 = BF_SUBTASKS(task, block);
  680.         while (task2 != NULL_TASK) {
  681.             i = 0; 
  682.             j = 0;
  683.             while (i < RTS_MULT(TCB_RTS_ITEM(task2)))
  684.                 if ((dep=RTS_TCBS(TCB_RTS_ITEM(task2),j++)) != NULL_TASK) {
  685.                     i++;
  686.                     kill(dep);
  687.                 }
  688.             task2 = TCB_BROTHER(task2);
  689.         }
  690.         block = BF_PREVIOUS_BFP(task, block);
  691.     }
  692.     /* STEP 3: Perform cleanup. Try to disable task if it waiting, if
  693.      *    successful then must signal.  Otherwise it will discover itself when
  694.      *     awakens. 
  695.      */
  696.     switch (TCB_STATUS(task)) {
  697.     case COMPLETED  :
  698.     case ACTIVATING :                        
  699.         break;
  700.     case SELECTING_TERM:
  701.     case SELECTING_NOTERM:
  702.         if (FAS(&(TCB_RDV(task)),0) == 1)
  703.             make_ready(task, ABORT_EVENT);            
  704.         break;
  705.     case TIMED_RDV:
  706.     case CALLING_RDV:
  707.         if (eremove(task)) make_ready(task, ABORT_EVENT); 
  708.         break;
  709.     case WAIT:
  710.         if (remove_io(&(TCB_IO_ITEM(task))))
  711.             make_ready(task, ABORT_EVENT);            
  712.         break;
  713.     default: 
  714.         raise(SYSTEM_ERROR, "Aborting task in unknown state");
  715.         break;
  716.     }
  717. }
  718.  
  719. /*--------------------------------------------------------------------------*/
  720. /*                       ABORTME                                             */
  721. /* Task has discovered it was aborted. kids in select term have been sig-   */
  722. /* nalled.  Completed kids will be notified when their kids are through.    */
  723. /* My terminated kids are already done.                                     */
  724. /*--------------------------------------------------------------------------*/
  725.  
  726. static void abortme()                            /*;abortme */
  727. {
  728.     purge_rdv(tp);
  729.     if ((MY_STATUS != QUIESCENT) && (DEC(MY_NUM_NOTERM) != 1)) {
  730.         MY_STATUS = COMPLETED;
  731.         schedule(ABORT_ONE);
  732.     }
  733.     else post_abort_one();
  734. }
  735.  
  736. static void post_abort_one()                                /*;post_abort_one*/
  737. {
  738.     if (MY_STATUS != QUIESCENT)
  739.         check_termination(MY_MASTER_TASK, MY_MASTER_BLOCK);
  740.     task_term();    /* not strictly needed for abort, just "term-wave" */
  741. }
  742.  
  743. /*--------------------------------------------------------------------------*/
  744. /*                           T E R M I N A T I O N                          */
  745. /*                                                                          */
  746. /*  The following set of routines maintain the counters and data structures */
  747. /*  used to perform task temination.  They are divided into two sets: those */
  748. /*  used in the termination of blocks and subprograms and those used in the */
  749. /*  termination of tasks.                                                   */
  750. /*--------------------------------------------------------------------------*/
  751.  
  752.  
  753. /*--------------------------------------------------------------------------*/
  754. /*                          COMPLETE  TASK                                  */
  755. /*  This is the last instruction in a task's instruction stream             */
  756. /*--------------------------------------------------------------------------*/
  757.  
  758. void complete_task()                                        /*;complete_task*/
  759. {
  760.     MY_STATUS = COMPLETED;
  761.     if (DEC(MY_NUM_NOTERM) != 1) schedule(COMPLETE_TASK_ONE);
  762.     else post_complete_task_one();
  763. }
  764.  
  765. static void post_complete_task_one()                /*;post_complete_task_one*/
  766. {
  767.     check_termination(MY_MASTER_TASK, MY_MASTER_BLOCK);
  768.     if (INC(MY_ABNORMAL) == 0)
  769.         task_term();
  770.     else if (DEC(MY_NUM_DEPS) != 1) schedule(FREE_TASK_SPACE);
  771.     else free_task_space();
  772. }
  773.  
  774. /*--------------------------------------------------------------------------*/
  775. /*                              COMPLETE  BLOCK                             */
  776. /*--------------------------------------------------------------------------*/
  777.  
  778. void complete_block()                                        /*;complete_block*/
  779. {
  780.     MY_STATUS = COMPLETE_BLOCK;
  781.     if (DEC(MY_BF_NUM_NOTERM) != 1)
  782.         schedule(COMPLETE_BLOCK_ONE);
  783.     else post_complete_block();
  784. }
  785.  
  786. static void post_complete_block()                        /*;post_complete_block*/
  787. {
  788.     if (MY_ABNORMAL == 0)
  789.         tell_termination(*MY_BLOCK_PTR);
  790.     if (DEC(MY_BF_NUM_DEPS) != 1)    schedule(COMPLETE_BLOCK_TWO);
  791.     else post_complete_block_two();
  792. }
  793.  
  794. static void post_complete_block_two()            /*;post_complete_block_two*/
  795. {
  796.     MY_STATUS = ACTIVE;
  797. }
  798.  
  799. /*--------------------------------------------------------------------------*/
  800. /*                     TERMINATION  SUPPORT  ROUTINES                       */
  801. /*--------------------------------------------------------------------------*/
  802.  
  803. static void task_term()                                            /*;task_term*/
  804. {
  805.     int block;
  806.  
  807.     if (DEC(MY_NUM_DEPS) != 1) {
  808.         block = *MY_BLOCK_PTR;
  809.         while (block != 0) {
  810.             tell_termination(block);
  811.             block = BF_PREVIOUS_BFP(tp, block);
  812.         }
  813.         schedule(FREE_TASK_SPACE);
  814.     }
  815.     else free_task_space();
  816. }
  817.  
  818. static void free_task_space()                            /*;free_task_space */
  819. {
  820.     int    block;
  821.  
  822.     block = *MY_BLOCK_PTR;
  823.     while (block != 0) {
  824.         uncreate_tasks(BF_SUBTASKS(tp, block));
  825.         block = BF_PREVIOUS_BFP(tp, block);
  826.     }
  827.     MY_STATUS = TERMINATED;
  828.     check_done(MY_MASTER_TASK, MY_MASTER_BLOCK);
  829.     schedule(NO_ACTION);
  830. }
  831.  
  832. /* Recursive procedure to check master tasks and blocks called by quiescent */
  833. /* dependent of "task" and "block"                         */
  834.  
  835. static void check_termination(int task, int block)        /*;check_termination */
  836. {
  837.     if ((task != NULL_TASK) && (task != 0) && (DEC(TCB_NUM_NOTERM(task)) == 1))
  838.         if ((TCB_STATUS(task) == COMPLETED) && (INC(TCB_FIRST(task)) == 0)) {
  839.             if (TCB_NUM_NOTERM(task) == 0)
  840.                 make_ready(task, TERMINATE_EVENT);
  841.         }
  842.         else
  843.             check_termination(TCB_MASTER_TASK(task),TCB_MASTER_BLOCK(task));
  844.  
  845.     if ((block != 0) && (DEC(BF_NUM_NOTERM(task, block)) == 1))
  846.         make_ready(task, TERMINATE_EVENT);
  847. }
  848.  
  849. static void check_done(int task, int block)                        /*;check_done*/
  850. {
  851.     int    dd;
  852.     dd = DEC(TCB_NUM_DEPS(task));
  853.     if ((DEC(BF_NUM_DEPS(task, block)) == 1) || (dd == 1))
  854.         make_ready(task, NO_EVENT);
  855. }
  856.  
  857. static void check_unterm()                                    /*;check_unterm*/
  858. {
  859.     if (INC(MY_NUM_NOTERM) == 0) {
  860.         INC(TCB_NUM_NOTERM(MY_MASTER_TASK));
  861.         INC(BF_NUM_NOTERM(MY_MASTER_TASK, MY_MASTER_BLOCK));
  862.     }
  863. }
  864.  
  865. static void tell_termination(int block)                    /*;tell_termination*/
  866. {
  867.     int i, j, dep, task;
  868.  
  869.     task = BF_SUBTASKS(tp, block);
  870.     while (task != NULL_TASK) {
  871.         i = 0; 
  872.         j = 0;
  873.         while (i < RTS_MULT(TCB_RTS_ITEM(task)))
  874.             if ((dep=RTS_TCBS(TCB_RTS_ITEM(task),j++)) != NULL_TASK) {
  875.                 i++;
  876.                 if ((TCB_STATUS(dep) != TERMINATED)
  877.                   && (INC(TCB_ABNORMAL(dep)) == 0))
  878.                     make_ready(dep, TERMINATE_EVENT);
  879.             }
  880.         task = TCB_BROTHER(task);
  881.     }
  882. }
  883.  
  884. /* Procedure used when an exception is raised to terminate tasks that have
  885.  * created, but not yet activated.(LRM 9.3(4)) Such tasks may have pending
  886.  * rendezvous. All tasks linked to task frames depending on the current BFP
  887.  * are made terminated. They are linked together and put on bf_subtasks in
  888.  * order to release their space when the block is exited.
  889.  */
  890.  
  891. void terminate_unactivated()                     /*;terminate_unactivated */
  892. {
  893.     int     current, next, removed, dep, i, j;
  894.     int    *task_frame;
  895.  
  896.     task_frame = MY_TASKS_DECLARED;
  897.     if (task_frame != (int *)0) {
  898.         removed = NULL_TASK;
  899.         *(task_frame - WORDS_PTR - 1) = -(*(task_frame - WORDS_PTR - 1));
  900.         for (;;) {
  901.             current = *task_frame;
  902.             if (current != NULL_TASK) {
  903.                 for (;;) {
  904.                     i = 0; 
  905.                     j = 0;
  906.                     while (i < RTS_MULT(TCB_RTS_ITEM(current)))
  907.                         if ((dep=RTS_TCBS(TCB_RTS_ITEM(current),j++))
  908.                           != NULL_TASK) {
  909.                             i++;
  910.                             TCB_STATUS(dep) = TERMINATED;
  911.                             purge_rdv(dep);
  912.                         }
  913.                     next = TCB_BROTHER(current);
  914.                     if (next == NULL_TASK)
  915.                         break;
  916.                     current = next;
  917.                 }
  918.  
  919.                 /* we are still in the context of the last task on the chain
  920.                  * merge the chain with previous one
  921.                  */
  922.  
  923.                 TCB_BROTHER(current) = removed;
  924.                 removed = *task_frame;/* head of the chain */
  925.             }
  926.             task_frame = *((int **)(task_frame - WORDS_PTR));
  927.             if (task_frame == (int *)0)
  928.                 break;
  929.         }
  930.  
  931.         if (removed != NULL_TASK)  /* merge on bf_subtasks to release space */
  932.             MY_SUBTASKS = union_tasks_declared(removed, MY_SUBTASKS);
  933.         MY_TASKS_DECLARED = (int *)0;
  934.     }
  935. }
  936.  
  937. /* Procedure to raise TASKING_ERROR in all tasks waiting for or engaged   */
  938. /* in a rendezvous with the currently active task                         */
  939.  
  940. void purge_rdv(int curr)                                        /*;purge_rdv */
  941. {
  942.     int     task, i;
  943.  
  944.     for (i = 1; i <= TCB_NUM_ENTRIES(curr); i++)
  945.         while (ENTRY_COUNT(TCB_ENTRY(curr,i)) > 0) {
  946.             DEC(ENTRY_COUNT(TCB_ENTRY(curr,i)));
  947.             if ((task = eget(TCB_ENTRY(curr,i))) != NULL_TASK) {
  948.                 TCB_EXCEPTION(task) = TASKING_ERROR;
  949.                 make_ready(task, TASKERR_EVENT);
  950.             }
  951.         }
  952.  
  953.     task = TCB_SERVICED(curr);
  954.     while (task != NULL_TASK) {
  955.         TCB_EXCEPTION(task) = TASKING_ERROR;
  956.         make_ready(task, TASKERR_EVENT);
  957.         task = TCB_NEXT(task);
  958.     }
  959. }
  960.  
  961. static void uncreate_tasks(int task_list)                /*;uncreate_tasks */
  962. {
  963.     int        task, next, i, j;
  964.     struct rts_item    *item;
  965.  
  966.     task = task_list;
  967.     while (task > 0) {
  968.         next = TCB_BROTHER(task);
  969.         item = TCB_RTS_ITEM(task);
  970.         i = 0; 
  971.         j = 0;
  972.         while (i < RTS_MULT(item))
  973.             if ((task = RTS_TCBS(item,j++)) != NULL_TASK) {
  974. #ifdef TRACE
  975.                 if (signal_trace)
  976.                     printf("task %d releasing space of %d \n ", tp, task);
  977. #endif
  978.                 i++;
  979.                 efree((char *) STACK(task));
  980.                 STACK(task) = (int *) 0;
  981.                 ORIG(task) = NULL_TASK;
  982.             }
  983.         task = next;
  984.     }
  985. }
  986.  
  987. /*--------------------------------------------------------------------------*/
  988. /*                  T I M E   M A N A G E M E N T                           */
  989. /*                                                                          */
  990. /*      The following set of routines perform time management for "delay"   */
  991. /*  statements.   The chain of waiting tasks associated with each PE        */
  992. /*  is sorted in ascending time of end of delay.  The time associated       */
  993. /*  with each entry in the chain in the amount of time it must wait after   */
  994. /*  the previous entry is done (e.g.  the wait time is kept incrementally)  */
  995. /*  A global variable "next_clock" keeps the absolute time value of the next*/
  996. /*  interrupt.  When the interrupt processing routine is called all interupt*/
  997. /*  which are now ready -or- were previously ready are made ready.          */
  998. /*    Io_items are freed by either the owning task or the interrupt           */
  999. /*  process.  If the io_item has been disabled, it is freed by the catcher  */
  1000. /*  routine.  Otherwise it is freed by the process when it awakens from     */
  1001. /*  make ready.                                                             */
  1002. /*--------------------------------------------------------------------------*/
  1003.  
  1004.  
  1005. static void my_set_timer(struct io_item_type *item, long now) /*;my_set_timer*/
  1006. {
  1007.     next_clock = II_DELTA(item) + now;
  1008. }
  1009.  
  1010. static int long my_reset_timer(long now)                /*;my_reset_timer*/
  1011. {
  1012.     last_time = now;
  1013.     return(next_clock - now);
  1014. }
  1015.  
  1016. /*--------------------------------------------------------------------------*/
  1017. /*                              DELAY_STMT                                  */
  1018. /*  Guarantees that all wait times are positive (provided for compatability)*/
  1019. /*  Note that it recognizes three types of delays:                          */
  1020. /*      0       - signifies simply a request to context switch              */
  1021. /*      ENDLESS - signifies simply relinquishing the CPU                    */
  1022. /*      other   - actual create a timer chain element and chain it          */
  1023. /*--------------------------------------------------------------------------*/
  1024.  
  1025. void delay_stmt(long delay_time)                                /*;delay_stmt*/
  1026. {
  1027.     long effective_delay;
  1028.  
  1029.     effective_delay = delay_time >= 0 ? delay_time : 0;
  1030. #ifdef TRACE
  1031.     if (rendezvous_trace) {
  1032.         printf("task %d delaying %ld effective delay %ld \n", tp,
  1033.           delay_time, effective_delay);
  1034.     }
  1035. #endif
  1036.     if (effective_delay == (long) ENDLESS)
  1037.         schedule(NO_ACTION);
  1038.     else if (effective_delay == 0)
  1039.         context_switch();
  1040.     else
  1041.         wait(effective_delay, WAIT);
  1042. }
  1043.  
  1044. /*--------------------------------------------------------------------------*/
  1045. /*                                 WAIT                                     */
  1046. /*  Routines which makes the task wait for the delay time                   */
  1047. /*--------------------------------------------------------------------------*/
  1048.  
  1049. static void wait(long delay, int action)                             /*;wait*/
  1050. {
  1051.     MY_STATUS = WAIT;
  1052.     if (MY_ABNORMAL && MY_STATUS != TERMINATED) { 
  1053.         abortme(); 
  1054.         return; 
  1055.     }
  1056.     MY_IO_ITEM = chain(tp, delay);
  1057.     schedule(action);
  1058. }
  1059.  
  1060. static void post_wait()                                            /*;post_wait*/
  1061. {
  1062.     MY_STATUS = ACTIVE;
  1063.     if (MY_ABNORMAL) 
  1064.         abortme(); 
  1065. }
  1066.  
  1067. /*--------------------------------------------------------------------------*/
  1068. /*                              CATCHER                                     */
  1069. /* Routine called when a timer interrupt occurs.                           */
  1070. /*--------------------------------------------------------------------------*/
  1071.  
  1072. void clock_interrupt(long now_time)                     /*;clock_interrupt*/
  1073. {
  1074.     catcher(now_time);
  1075.     context_switch();
  1076. }
  1077.  
  1078. static void catcher(long now_time)                                 /*;catcher*/
  1079. {
  1080.     struct io_item_type    *item;
  1081.     long            time;
  1082.  
  1083.     /* Time Out head of io_item list and all others following with delta 0 */
  1084.     time = now_time - last_time;
  1085.     last_time = now_time;
  1086.  
  1087.     while ((clock_head != NULL) && (II_DELTA(clock_head)<=time)) {
  1088.         item = II_NEXT(clock_head);  /* TO others waiting in interval */
  1089.         time -= II_DELTA(clock_head);
  1090.         check_free(clock_head);
  1091.         clock_head = item;
  1092.     }
  1093.  
  1094.     /* remove interior deletes from head of list */
  1095.  
  1096.     item = clock_head;
  1097.     while ((clock_head != NULL) && (II_FLAG(clock_head) == 0)) {
  1098.         time -= II_DELTA(clock_head);
  1099.         item = II_NEXT(clock_head);
  1100.         efree((char *) clock_head);
  1101.         clock_head = item;
  1102.     }
  1103.     if (clock_head != NULL) {
  1104.         II_DELTA(clock_head) -= time;
  1105.         my_set_timer(clock_head, now_time);
  1106.     }
  1107.     else next_clock_flag = FALSE;
  1108. }
  1109.  
  1110. /*--------------------------------------------------------------------------*/
  1111. /*                                CHAIN                                     */
  1112. /*  Called when execute a delay.  Add task to timeout chain                 */
  1113. /*--------------------------------------------------------------------------*/
  1114.  
  1115. static struct io_item_type *chain(int task, long delay)         /*;chain*/
  1116. {
  1117.     long    my_reset_time(), itime();
  1118.     long    now;
  1119.     struct io_item_type *new_item, *item, *prev_item;
  1120.  
  1121.     now = itime() + time_offset;
  1122.     if (TCB_IO_ITEM(task) == NULL) {
  1123.         new_item=(struct io_item_type *)malloc(sizeof(struct io_item_type));
  1124.         if (new_item == (struct io_item_type *)0) {
  1125.             raise(STORAGE_ERROR, "Allocating space for timer chain");
  1126.             return(NULL);
  1127.         }
  1128.     }
  1129.     else new_item = TCB_IO_ITEM(task);
  1130.     if (clock_head == NULL) {
  1131.         clock_head = new_item;
  1132.         II_TASK(new_item) = task;
  1133.         II_FLAG(new_item) = TCB_STATUS(task);
  1134.         II_NEXT(new_item) = NULL;
  1135.         II_DELTA(new_item) = delay;
  1136.     }
  1137.     else {
  1138.         II_DELTA(clock_head) = my_reset_timer(now); /* time in intval*/
  1139.         II_TASK(new_item) = task;
  1140.         II_FLAG(new_item) = TCB_STATUS(task);
  1141.  
  1142.         /* seq. search for new_item's position based on relative deltas */
  1143.         if (delay <= II_DELTA(clock_head)) {
  1144.             II_NEXT(new_item) = clock_head;
  1145.             II_DELTA(new_item) = delay;
  1146.             II_DELTA(clock_head) -= delay;
  1147.             clock_head = new_item;
  1148.         }
  1149.         else {
  1150.             item = clock_head;
  1151.             prev_item = clock_head;
  1152.             while ((item != NULL) && (delay-II_DELTA(item) > 0)) {
  1153.                 delay -= II_DELTA(item);
  1154.                 prev_item = item;
  1155.                 item = II_NEXT(item);
  1156.             }
  1157.             II_NEXT(new_item) = item;
  1158.             II_NEXT(prev_item) = new_item;
  1159.             II_DELTA(new_item) = delay;
  1160.             if (item != NULL)
  1161.                 II_DELTA(item) -= delay;
  1162.         }
  1163.     }
  1164.     next_clock_flag = TRUE;
  1165.     my_set_timer(clock_head, now);
  1166.     return(new_item);
  1167. }
  1168.  
  1169. /*--------------------------------------------------------------------------*/
  1170. /*                              CHECK  FREE                                 */
  1171. /* Called by catcher to see if timeout is possible                          */
  1172. /*--------------------------------------------------------------------------*/
  1173.  
  1174. static void check_free(struct io_item_type *item)                /*;check_free*/
  1175. {
  1176.     int    value;
  1177.  
  1178.     value = get_io(item);
  1179.     if (value > 0)     /* anything else being waited for has been disble */
  1180.         make_ready(II_TASK(item), TIMER_EVENT);
  1181.  
  1182.     /*  Originally we were going to deallocate the io_item.  This was later
  1183.      *  changed EXCEPT in the case where it was already disabled ...
  1184.      */
  1185.     else if (value == -1)
  1186.         efree((char *) item);
  1187. }
  1188.  
  1189. /*--------------------------------------------------------------------------*/
  1190. /*                                GET  IO                                   */
  1191. /*--------------------------------------------------------------------------*/
  1192.  
  1193. static int get_io(struct io_item_type *item)                        /*;get_io*/
  1194. {
  1195.     int    wake;
  1196.  
  1197.     switch (FAS(&(II_FLAG(item)),TIMER_EVENT)){  /* was task's status */
  1198.     case DISABLED_EVENT:  
  1199.         wake = -1; 
  1200.         break;      /* already gone */
  1201.     case TIMED_RDV :      
  1202.         wake = eremove(II_TASK(item));
  1203.         FAS(&(II_FLAG(item)), 0);        
  1204.         break;
  1205.     case SELECTING_NOTERM:                 /* disable */
  1206.     case SELECTING_TERM:  
  1207.         wake = FAS(&(TCB_RDV(II_TASK(item))),0);
  1208.         FAS(&(II_FLAG(item)), 0);        
  1209.         break;
  1210.     case WAIT :           
  1211.         wake = 1; 
  1212.         break;        /* must wake up */
  1213.     case 0    :           
  1214.         wake = -1; 
  1215.         break;       /* innner remove*/
  1216.     default :             
  1217.         raise(SYSTEM_ERROR, "Unexpected event");
  1218.         break;
  1219.     }
  1220.     II_FLAG(item) = 0;
  1221.     return wake;
  1222. }
  1223.  
  1224.  
  1225. /*--------------------------------------------------------------------------*/
  1226. /*                             DISABLE IO                                   */
  1227. /* Called when rdv ti disable timeouts.  No timeouts possible, but avoids   */
  1228. /* race (that item.flag may be gotten, rendezvous, then RDV reset for next  */
  1229. /* rendezvous).                                                             */
  1230. /*--------------------------------------------------------------------------*/
  1231.  
  1232. static void disable_io(struct io_item_type **item_ptr)            /*;disable_io*/
  1233. {
  1234.     struct io_item_type    *item;
  1235.  
  1236.     item = *item_ptr;
  1237.     if (item != (struct io_item_type*)0) {
  1238.         if (FAS(&(II_FLAG(item)),DISABLED_EVENT) == TIMER_EVENT) {
  1239.             /* Timeout in progress, wait for it to end then delete */
  1240.             while (II_FLAG(item) != 0) continue;
  1241.             efree((char *) item);
  1242.         }
  1243.         *item_ptr =(struct io_item_type *)0 ;
  1244.     }
  1245. }
  1246.  
  1247. /*--------------------------------------------------------------------------*/
  1248. /*                             REMOVE  IO                                   */
  1249. /* Called when abort in delay                                               */
  1250. /*--------------------------------------------------------------------------*/
  1251.  
  1252. static int remove_io(struct io_item_type **item_ptr)            /*;remove_io */
  1253. {
  1254.     struct io_item_type    *item;
  1255.  
  1256.     item = *item_ptr;
  1257.     if (item != (struct io_item_type *)0)
  1258.         if (FAS(&(II_FLAG(item)),DISABLED_EVENT) == TIMER_EVENT) {
  1259.             efree((char *) item);  /* too late, has timed out ... */
  1260.             *item_ptr = (struct io_item_type *)0;
  1261.             return 0;
  1262.         }
  1263.     return 1;
  1264. }
  1265.  
  1266. /*--------------------------------------------------------------------------*
  1267.  *                           S C H E D U L E R                              *
  1268.  *                                                                          *
  1269.  *  The following set of routines perform decentrallized scheduling based   *
  1270.  *  on "run-until-blocked".  Because the interpreter simply simulates tasks *
  1271.  *  it is absolutely necessary that once "schedule" is call and control is  *
  1272.  *  passed to a new virtual task, that the interpretor return to the highest*
  1273.  *  level without executing any other code (excepting the cleanup routines  *
  1274.  *  called in "schedule".  Thus any statement which (recursively) executes  *
  1275.  *  "schedule" must be immediately succeeded by a return statement.  The    *
  1276.  *  "dangerous" routines in the system are:                                 *
  1277.  *    - abort                - abortme                                            *
  1278.  *    - wait                 - post_wait             - delay_stmt                    *
  1279.  *    - complete_block    - task_complete        - termflags_on_wait             *
  1280.  *    - entry_call            - post_entry_call    - end_rendezvous                *
  1281.  *    - selective_wait    - post_selective_wait                                *
  1282.  *--------------------------------------------------------------------------*/
  1283.  
  1284. /*--------------------------------------------------------------------------*
  1285.  *                             SCHEDULE                                     *
  1286.  * Block the currently executing task and select a new task to run.         *
  1287.  *--------------------------------------------------------------------------*/
  1288.  
  1289. static void schedule(int action)                                /*;schedule*/
  1290. {
  1291.     int     done, p, i;
  1292.     struct rts_item    *item;
  1293.  
  1294.     MY_ACTION = action;
  1295.     if (DEC(MY_NUM_EVENTS) > 0) {
  1296.         finish_action(MY_RTS_ITEM);  /* an event is waiting */
  1297.         return;
  1298.     }
  1299.     if (action == CONTEXT_SWITCH) INC(MY_NUM_EVENTS);
  1300.     done = FALSE;
  1301.     while (!done) {
  1302.         for (p=MAX_PRIO-1;p>=0;p--) {
  1303.             item = dequeue(ready_queue[p], &i);
  1304.             if (item != (struct rts_item *)0) {
  1305.                 switch(RTS_TYPE(item)) {
  1306.                 case ACTIVATE :
  1307.                 case READY :
  1308. #ifdef TRACE
  1309.                     if (signal_trace) {
  1310.                         printf("task %d switching to task %d \n \n",
  1311.                           tp,item->tcbs[i]);
  1312.                     }
  1313. #endif
  1314.                     highest_priority = p;
  1315.                     transfer(item->tcbs[i]);
  1316.                     done = TRUE;                 
  1317.                     break;
  1318.                 case CREATE :
  1319.                     create_task(RTS_TEMPL_BASE(item),
  1320.                         RTS_TEMPL_OFF(item),item,i); 
  1321.                     break;
  1322.                 default :
  1323.                     raise(SYSTEM_ERROR, "Unexpected type"); 
  1324.                     break;
  1325.                 }
  1326.                 break;   /* out of for loop */
  1327.             }
  1328.             else if (p == 0) done = TRUE;  /* end loop (error) */
  1329.         }
  1330.     }
  1331.  
  1332.     if (item == (struct rts_item *)0)
  1333.     { /* No active task was found, error condition */
  1334.         MY_STATUS = ACTIVE;
  1335.         raise(SYSTEM_ERROR, "No activatable task");
  1336.         MY_EXCEPTION = 0;
  1337.         return;
  1338.     }
  1339.     finish_action(item);
  1340. }
  1341.  
  1342. /* Now the new task is processing.  It must perform the appropriate   */
  1343. /* cleanup routine based on the action which it was performing before */
  1344. /* making the call to the scheduler ...                      */
  1345.  
  1346. static void finish_action(struct rts_item *item)            /*;finish_action*/
  1347. {
  1348.     int    open_en[MAX_ALTS], accept_index[MAX_ALTS];
  1349.     long     sleep_time;
  1350.     long    itime();
  1351.  
  1352.     switch (MY_ACTION) {
  1353.     case WAIT         : 
  1354.         post_wait();             
  1355.         break;
  1356.     case SELECTIVE_WAIT     : 
  1357.         post_selective_wait(0, 0, open_en, accept_index);         
  1358.         break;
  1359.     case ENTRY_CALL     : 
  1360.         post_entry_call();         
  1361.         break;
  1362.     case COMPLETE_BLOCK_ONE    : 
  1363.         post_complete_block();     
  1364.         break;
  1365.     case COMPLETE_BLOCK_TWO : 
  1366.         post_complete_block_two(); 
  1367.         break;
  1368.     case ABORT_ONE        : 
  1369.         post_abort_one();         
  1370.         break;
  1371.     case COMPLETE_TASK_ONE    : 
  1372.         post_complete_task_one();    
  1373.         break;
  1374.     case FREE_TASK_SPACE     : 
  1375.         free_task_space();    
  1376.         break;
  1377.     case DONE_ACTIVATION    : 
  1378.         done_activation();        
  1379.         break;
  1380.     case DONE_CREATION       : 
  1381.         done_creation();        
  1382.         break;
  1383.     case ACTIVATE_SELF      : 
  1384.         activate_self(RTS_MASTER_TASK(item), RTS_MASTER_BLOCK(item)); 
  1385.         break;
  1386.     case CONTEXT_SWITCH    :
  1387.     case NO_ACTION       :                 
  1388.         break;
  1389.     default : 
  1390.         raise(SYSTEM_ERROR, "Tasks awakened in an unknown state");
  1391.         MY_EXCEPTION = 0;                 
  1392.         break;
  1393.     }
  1394.  
  1395.     /* then see if someone else waiting to be scheduled */
  1396.  
  1397.     if (tp == 0) {        /* we schedule IDLE */
  1398.         if (next_clock_flag) {           /* exists task waiting? */
  1399.             if (simul_time_flag)         /* speed up time! */
  1400.                 time_offset += next_clock - itime();
  1401.             else if ((sleep_time=(next_clock-itime())/1000L) > 1L)
  1402.                 sleep((unsigned)sleep_time);
  1403.         }
  1404.         else if ((MY_ACTION != DONE_CREATION) && (MY_ACTION != DONE_ACTIVATION))
  1405.             raise(PROGRAM_ERROR, "System inactive(deadlock)");
  1406.     }
  1407.     MY_ACTION = NO_ACTION;
  1408. }
  1409.  
  1410. /*--------------------------------------------------------------------------*/
  1411. /*                              MAKE READY                                  */
  1412. /* Moves the specified task to the ready queue setting it's event flag.     */
  1413. /*--------------------------------------------------------------------------*/
  1414.  
  1415. static void make_ready(int task, int event)                    /*;make_ready*/
  1416. {
  1417.     if (event != NO_EVENT) /* Mulitple events may overwrite (COMP,TERM,ABORT) */
  1418.         TCB_EVENT(task)=event;  /* but task can tell if correct one happened */
  1419.  
  1420.     if (INC(TCB_NUM_EVENTS(task)) == -1) enqueue(TCB_PRIO(task), task);
  1421. }
  1422.  
  1423. /*---------------------------------------------------------------------------*/
  1424. /*                              TRANSFER                                     */
  1425. /*  Transfers control from the currently executing task to the one specified */
  1426. /*---------------------------------------------------------------------------*/
  1427.  
  1428. static void transfer(int new_task)                          /*;transfer*/
  1429. {
  1430.     PUSH(exr);
  1431.     PUSH(lin);
  1432.     PUSH(sfp);
  1433.     PUSH(cs);
  1434.     PUSH(ip);
  1435.     PUSH(bfp);    /*  ----------MUST be on top of stack----------  */
  1436.     MY_BLOCK_PTR = (int *) (cur_stack+cur_stackptr);
  1437.     STACKPTR(tp) = cur_stackptr;
  1438.  
  1439.     tp = new_task;
  1440.     cur_stack = STACK(tp);
  1441.     cur_stackptr = STACKPTR(tp);
  1442.     POP(bfp);
  1443.     MY_BLOCK_PTR = &bfp;
  1444.     POP(ip);
  1445.     POP(cs);
  1446.     POP(sfp);
  1447.     POP(lin);
  1448.     POP(exr);
  1449.     cur_code = code_segments[cs];
  1450. }
  1451.  
  1452. /*--------------------------------------------------------------------------*
  1453.  *                           R E N D E Z V O U S                            *
  1454.  *                                                                          *
  1455.  * The following set of procedures are used to performs rendezvous.  They   *
  1456.  * are divided into two sets: those used to perform a "select" call and     *
  1457.  * those used to execute an "entry" call.    They make use of the parallel  *
  1458.  * queue routines and use the "rdv" flag, the array of "entry" records, the *
  1459.  * "io_item" when processing delays as well as checking and setting the     *
  1460.  * "status" and "abnormal" fields in the caller and/or owner task's TCB.    *
  1461.  * The routines which are called by the interpretor directly are:           *
  1462.  *     - selective_wait                                                        *
  1463.  *     - end_rendezvous                                                        *
  1464.  *     - entry_call                                                            *
  1465.  * There calling interface (stack upon entry and return as well as parms.   *
  1466.  * passed are identical to the original system.                             *
  1467.  *--------------------------------------------------------------------------*/
  1468.  
  1469.  
  1470. /*--------------------------------------------------------------------------*
  1471.  *                          SELECTIVE WAIT                                  *
  1472.  *--------------------------------------------------------------------------*/
  1473.  
  1474. void selective_wait(int num_alts)                            /*;selective_wait */
  1475. {
  1476.     int    alt_kind;        /* delay, terminate or accept */
  1477.     long    delay_time;        /* value of delay */
  1478.     long    min_delay;        /* minimum delay */
  1479.     int    family;            /* family index of entry */
  1480.     int    member;            /* member of family */
  1481.     int    guard;            /* guard of statement (boolean) */
  1482.     int    open_ai[MAX_ALTS];    /* list of open accept indices */
  1483.     int    open_en[MAX_ALTS];    /* list of open entry numbers  */
  1484.     int    num_open_alts;        /* number of open alternatives */
  1485.     int    delay_index;        /* index to delay alt. (or -1) */
  1486.     int    term_index;        /* index to terminate alt. (or -1) */
  1487.     int    accept_index;        /* index to chosen alternative */
  1488.     int     caller;            /* chosen task id of caller */
  1489.     struct entry_type *entry;    /* pointer to entry */
  1490.     int     i, temp;
  1491.  
  1492.  
  1493.     /*  STEP 1: Build a set of open alternatives and determine the shortest
  1494.      * delay and the index set of the terminate (if any)
  1495.      */
  1496.  
  1497.     term_index = -1;
  1498.     min_delay = ENDLESS;
  1499.     delay_index = -1;
  1500.  
  1501.     if (num_alts == 0) {  /* simple accept */
  1502.         POP(member);
  1503.         POP(family);
  1504.         num_open_alts = 1;
  1505.         open_ai[0] = 1;
  1506.         open_en[0] = entry_number(tp, family, member);
  1507.     }
  1508.     else num_open_alts = 0;
  1509.  
  1510.     for (accept_index = num_alts; accept_index >= 1; accept_index --) {
  1511.         POP(alt_kind);
  1512.         if (alt_kind == 1) {    /* accept */
  1513.             POP(member);
  1514.             POP(family);
  1515.             POP(guard);
  1516.             if (guard == 1) {
  1517.                 open_ai[num_open_alts] = accept_index;
  1518.                 open_en[num_open_alts++] = entry_number(tp, family, member);
  1519.             }
  1520.         }
  1521.         else if (alt_kind == 2) {    /* delay */
  1522.             POPL(delay_time);
  1523.             POP(guard);
  1524.             if (guard == 1)
  1525.                 if (delay_index == -1 || delay_time<min_delay) {
  1526.                     min_delay = (delay_time>=0L) ? delay_time : 0L;
  1527.                     delay_index = accept_index;
  1528.                 }
  1529.         }
  1530.         else if (alt_kind == 3) {    /* terminate */
  1531.             POP(guard);
  1532.             if (guard == 1)
  1533.                 term_index = accept_index;
  1534.         }
  1535.         else raise(SYSTEM_ERROR,
  1536.             "Unknown alternative in select statement");
  1537.     }
  1538.  
  1539.     /* STEP 2: Check local status, terminatability, guards, rdv flag etc.  */
  1540.  
  1541.     if (MY_ABNORMAL) { 
  1542.         abortme(); 
  1543.         return; 
  1544.     }
  1545.     MY_STATUS = SELECTING_NOTERM;
  1546.  
  1547.     evaluate_guards(open_en, num_open_alts);
  1548.  
  1549.     FAS(&(MY_RDV), 1);    /* an rdv is now possible     */
  1550.     if (MY_ABNORMAL && (FAS(&(MY_RDV), 0) == 1)) { 
  1551.         abortme(); 
  1552.         return; 
  1553.     }
  1554.  
  1555.     /* STEP 3: See if can start an immediate rendezvous */
  1556.  
  1557.     if (num_open_alts > 0) {
  1558.         i = 0;
  1559.         while (MY_RDV && (i < num_open_alts)) {
  1560.             temp = open_ai[i];
  1561.             entry = MY_ENTRY(open_en[i++]);
  1562.             if (ENTRY_GUARD(entry)) {
  1563.                 del_lock(&(LOCK(entry)));
  1564.                 if ((DEC(ENTRY_COUNT(entry)) > 0) && (FAS(&(MY_RDV),0) == 1)) {
  1565.                     /* a task is waiting and got flag so rdv is possible */
  1566.                     caller = eget(entry);
  1567.                     del_unlock(&(LOCK(entry)));
  1568.                     close_guards(open_en, num_open_alts);
  1569.                     TCB_SAVE_PRIO(caller) = MY_PRIO;
  1570.                     MY_PRIO = MAX(TCB_SAVE_PRIO(caller),MY_PRIO);
  1571.                     accept_rdv(caller,temp,num_alts);
  1572.                     return;
  1573.                 }
  1574.                 else {     /* we did not - disable the rendezvous...  */
  1575.                     INC(ENTRY_COUNT(entry));
  1576.                     del_unlock(&(LOCK(entry)));
  1577.                 }
  1578.             }
  1579.         }
  1580.     }
  1581.  
  1582.     /* STEP 4:  Unfortunately, couldn't perform rendezvous.  Now either detect
  1583.      *    an error condition, try to terminate or delay
  1584.      */
  1585.  
  1586.     if ((num_open_alts == 0) && (delay_index == -1) && (term_index == -1)){
  1587.         raise(PROGRAM_ERROR, "No open alternatives in select");
  1588.         return;
  1589.     }
  1590.  
  1591.     if (MY_RDV == 0) {     /* have been aborted or called, busywait */
  1592.         while ((MY_EVENT != RDV_EVENT) && (!MY_ABNORMAL)) continue;
  1593.         post_selective_wait(1, num_open_alts, open_en, open_ai);
  1594.     }
  1595.     else if ((min_delay == 0) && FAS(&(MY_RDV), 0) == 1) {
  1596.         MY_EVENT = TIMER_EVENT;
  1597.         open_en[num_open_alts] = TIMER_EVENT;
  1598.         open_ai[num_open_alts++] = delay_index;
  1599.         post_selective_wait(1, num_open_alts, open_en, open_ai);
  1600.         return;
  1601.     }
  1602.     else {
  1603.         if (num_alts != 0)    /* push open entry table on stack */
  1604.             for (i=0;i<num_open_alts;i++) {
  1605.                 PUSH(open_en[i]);
  1606.                 PUSH(open_ai[i]);
  1607.             }
  1608.         if (delay_index != -1) {
  1609.             PUSH(TIMER_EVENT);
  1610.             PUSH(delay_index);
  1611.             num_open_alts++;
  1612.         }
  1613.         if (term_index != -1) {
  1614.             PUSH(TERMINATE_EVENT);
  1615.             PUSH(term_index);
  1616.             MY_STATUS = SELECTING_TERM;
  1617.             if (DEC(MY_NUM_NOTERM) == 1)      /* am quiescent */
  1618.                 check_termination(MY_MASTER_TASK, MY_MASTER_BLOCK);
  1619.             num_open_alts++;
  1620.         }
  1621.         if (num_alts == 0)     /* simple accept */
  1622.             PUSH(0); 
  1623.         else  
  1624.             PUSH(num_open_alts); 
  1625.  
  1626. #ifdef TRACE
  1627.         if (rendezvous_trace)
  1628.             printf("task %d waiting for a rendezvous \n", tp);
  1629. #endif
  1630.         if (min_delay == ENDLESS) schedule(SELECTIVE_WAIT);
  1631.         else wait(min_delay, SELECTIVE_WAIT);
  1632.     }
  1633. }
  1634.  
  1635.  
  1636. /*--------------------------------------------------------------------------*/
  1637. /*                              EVALUATE GUARDS                             */
  1638. /*--------------------------------------------------------------------------*/
  1639.  
  1640. static void evaluate_guards(int open_en[], int num_open)    /*;evaluate_guards*/
  1641. {
  1642.     int i;
  1643.     struct entry_type    *entry;
  1644.  
  1645.     for (i=0;i< num_open;i++) {
  1646.         entry = MY_ENTRY(open_en[i]);
  1647.         del_lock(&(LOCK(entry)));
  1648.         ENTRY_GUARD(entry) = 1;
  1649.         del_unlock(&(LOCK(entry)));
  1650.     }
  1651. }
  1652.  
  1653. /*--------------------------------------------------------------------------*/
  1654. /*                            CLOSE  GUARDS                                 */
  1655. /*--------------------------------------------------------------------------*/
  1656.  
  1657.  
  1658. static void close_guards(int open_en[], int num_open)        /*;close_guards*/
  1659. {
  1660.     int i;
  1661.     struct entry_type    *entry;
  1662.  
  1663.     for (i=0;i< num_open;i++) {
  1664.         if ((open_en[i] != TERMINATE_EVENT) && (open_en[i] != TIMER_EVENT)){
  1665.             entry = MY_ENTRY(open_en[i]);
  1666.             del_lock(&(LOCK(entry)));
  1667.             ENTRY_GUARD(entry) = 0;
  1668.             del_unlock(&(LOCK(entry)));
  1669.         }
  1670.     }
  1671. }
  1672.  
  1673. /*--------------------------------------------------------------------------*/
  1674. /*                      POST  SELECTIVE  WAIT                               */
  1675. /*--------------------------------------------------------------------------*/
  1676.  
  1677. static void post_selective_wait(int in_mem, int num_alts, int open_en[],
  1678.   int open_ai[])                                    /*;post_selective_wait*/
  1679. {
  1680.     int    status, x, ai, accept_index;
  1681.  
  1682.     status = MY_STATUS;
  1683.     MY_STATUS = ACTIVE;
  1684.     if (MY_ABNORMAL) {
  1685.         if (status == SELECTING_TERM) MY_STATUS = QUIESCENT;
  1686.         abortme();
  1687.         return;
  1688.     }
  1689.     if (status == SELECTING_TERM) check_unterm();
  1690.  
  1691.     /* We must find the accept index for the selected alternative ... */
  1692.     if (MY_EVENT == TIMER_EVENT) MY_WHAT = TIMER_EVENT;
  1693.     accept_index = -1;
  1694.     if (in_mem) {
  1695.         if (num_alts != 0)
  1696.             for (x = 0; x < num_alts; x++)
  1697.                 if (open_en[x] == MY_WHAT) accept_index=open_ai[x];
  1698.     }
  1699.     else {
  1700.         POP(num_alts);
  1701.         if (num_alts != 0)
  1702.             for (x =0 ; x < num_alts; x++) {
  1703.                 POP(ai);
  1704.                 POP(open_en[x]);
  1705.                 if (open_en[x] == MY_WHAT) accept_index = ai;
  1706.             }
  1707.     }
  1708.  
  1709.     if ((num_alts != 0) && (accept_index == -1)) {
  1710.         raise(SYSTEM_ERROR, "Nonexistant alternative selected");
  1711.         return;
  1712.     }
  1713.     close_guards(open_en, num_alts);
  1714.  
  1715.     switch (MY_EVENT) {
  1716.     case TIMER_EVENT : 
  1717.         if (status == WAIT) {
  1718.             efree((char *) MY_IO_ITEM);
  1719.             MY_IO_ITEM = NULL;
  1720.         }
  1721.         PUSH(accept_index);             
  1722.         break;
  1723.     case RDV_EVENT :
  1724.         disable_io(&MY_IO_ITEM);
  1725.         accept_rdv(MY_WHO,accept_index,num_alts); 
  1726.         break;
  1727.     default          : 
  1728.         raise(SYSTEM_ERROR, 
  1729.             "Unexpected event in select/accept"); 
  1730.         break;
  1731.     }
  1732. }
  1733.  
  1734. /*--------------------------------------------------------------------------*/
  1735. /*                               ACCEPT                                     */
  1736. /*--------------------------------------------------------------------------*/
  1737.  
  1738. static void accept_rdv(int caller, int accept_index, int push_index)
  1739.                                                                 /*;accpt_rdv*/
  1740. {
  1741.     int    num_param;    /* number of parameters to transfer */
  1742.     int    disp, i;
  1743.  
  1744.     /* Must copy parameters over from the caller's stack */
  1745.  
  1746.     disp = STACKPTR(caller) - NB_REGISTERS;
  1747.     num_param = STACK(caller)[disp];
  1748.     disp -= num_param + 1;
  1749.     for (i = 1; i <= num_param; i++)
  1750.         PUSH(STACK(caller)[disp+i]);
  1751.  
  1752.     add_serviced(tp, caller);    /* may be nested rdv need if aborted */
  1753.     if (push_index)
  1754.         PUSH(accept_index);
  1755. }
  1756.  
  1757. /*--------------------------------------------------------------------------*/
  1758. /*                          END_RENDEZVOUS                                  */
  1759. /*--------------------------------------------------------------------------*/
  1760.  
  1761. void end_rendezvous()                                        /*;end_rendevous*/
  1762. {
  1763.     int    caller;
  1764.  
  1765.     caller = remove_serviced();
  1766. #ifdef TRACE
  1767.     if (rendezvous_trace)
  1768.         printf("task %d end rendezvous with task %d \n",tp, caller);
  1769. #endif
  1770.     MY_PRIO = TCB_SAVE_PRIO(caller);
  1771.     if (MY_EXCEPTION)           /* propagate exception to calling task */
  1772.         TCB_EXCEPTION(caller) = MY_EXCEPTION;
  1773.  
  1774.     make_ready(caller, ENDRDV_EVENT);
  1775.     if (MY_ABNORMAL) {              /* owner aborted, raise TASKING ERROR */
  1776.         TCB_EXCEPTION(caller) = TASKING_ERROR;
  1777.         abortme();
  1778.         return;
  1779.     }
  1780. }
  1781.  
  1782.  
  1783. /*--------------------------------------------------------------------------*/
  1784. /*                         ENTRY  CALL                                      */
  1785. /*--------------------------------------------------------------------------*/
  1786.  
  1787. void entry_call(long delay_time, int num_param)                    /*;entry_call*/
  1788. {
  1789.     struct entry_type *entry;
  1790.     int    owner;            /* owner of entry */
  1791.     int    family;            /* index of family of the entry */
  1792.     int    member;            /* index of member of the entry */
  1793.     int    entry_num;        /* actual entry number */
  1794.  
  1795.     /* STEP 1:  Get calling information from the stack */
  1796.  
  1797.     member = TOSM(num_param);
  1798.     family = TOSM(num_param + 1);
  1799.     owner  = TOSM(num_param + 2);
  1800.     if (owner != ORIG(owner) || STACK(owner) == (int *)0) {
  1801.         raise(TASKING_ERROR, "Call to an entry in a terminated task");
  1802.         return;
  1803.     }
  1804.     entry_num = entry_number(owner, family, member);
  1805.  
  1806. #ifdef TRACE
  1807.     if (rendezvous_trace)
  1808.         printf("task %d calling rendezvous with task %d entry %d\n",
  1809.           tp, owner, entry_num);
  1810. #endif
  1811.  
  1812.     /* STEP 2: Perform some error detection */
  1813.  
  1814.     if (entry_num > TCB_NUM_ENTRIES(owner)) {
  1815.         raise(SYSTEM_ERROR, "Nonexistant entry called");
  1816.         return;
  1817.     }
  1818.     if (TCB_STATUS(owner) == TERMINATED || TCB_ABNORMAL(owner)) {
  1819.         raise(TASKING_ERROR, "Call to an entry of a terminated task");
  1820.         return;
  1821.     }
  1822.  
  1823.     /* STEP 3: Set statuses */
  1824.  
  1825.     if (MY_ABNORMAL) { 
  1826.         abortme(); 
  1827.         return; 
  1828.     }
  1829.     if (delay_time == ENDLESS)
  1830.         MY_STATUS = CALLING_RDV;
  1831.     else MY_STATUS = TIMED_RDV;
  1832.     entry = TCB_ENTRY(owner, entry_num);
  1833.     PUSH(num_param);
  1834.     add_lock(&(LOCK(entry)));
  1835.  
  1836.     /* STEP 4:  See if immediate rendezvous */
  1837.  
  1838.     if ((INC(ENTRY_COUNT(entry)) == 0) && ENTRY_GUARD(entry) &&
  1839.       (FAS(&(TCB_RDV(owner)), 0) == 1)) {
  1840.         /* owner is commited to a rendezvous with the caller */
  1841.         DEC(ENTRY_COUNT(entry));    /* restore counter */
  1842.         TCB_WHAT(owner) = entry_num;
  1843.         TCB_WHO(owner) = tp;
  1844.         add_unlock(&(LOCK(entry)));
  1845.         disable_io(&(TCB_IO_ITEM(owner)));
  1846.         MY_SAVE_PRIO = TCB_PRIO(owner);
  1847.         TCB_PRIO(owner) = MAX(TCB_PRIO(owner),MY_PRIO);
  1848.         make_ready(owner, RDV_EVENT);
  1849.         schedule(ENTRY_CALL);        /* wait for end of rdv */
  1850.     }
  1851.  
  1852.     /* STEP 5: Cannot rendezvous immediately */
  1853.  
  1854.     else {    /* cannot immediately start a rendezvous */
  1855.         if (delay_time == 0) {   /* else changed to "delay 0" */
  1856.             DEC(ENTRY_COUNT(entry));
  1857.             add_unlock(&(LOCK(entry)));
  1858.             cur_stackptr -= 3;
  1859.             PUSH(0);
  1860.         }
  1861.         else {
  1862.             MY_CURR_ENTRY = entry;
  1863.             eput(entry, tp, &MY_ENTRY_ITEM);
  1864.             add_unlock(&(LOCK(entry)));
  1865.             if (MY_ABNORMAL && eremove(tp)) {
  1866.                 abortme();
  1867.                 return;
  1868.             }
  1869.             if (delay_time != ENDLESS)
  1870.                 MY_IO_ITEM = chain(tp, delay_time);
  1871.             schedule(ENTRY_CALL);
  1872.         }
  1873.     }
  1874. }
  1875.  
  1876. /*-------------------------------------------------------------------*/
  1877. /*                       POST  ENTRY  CALL                           */
  1878. /*-------------------------------------------------------------------*/
  1879.  
  1880. static void post_entry_call()                            /*;post_entry_call*/
  1881. {
  1882.     int    num_param;    /* number of parameters */
  1883.     int    i;
  1884.  
  1885.     POP(num_param);
  1886.     if (MY_ABNORMAL)  {
  1887.         disable_io(&MY_IO_ITEM);
  1888.         abortme();
  1889.         return;
  1890.     }
  1891.  
  1892.     i = MY_EVENT;
  1893.     switch (MY_EVENT) {
  1894.     case TIMER_EVENT : 
  1895.         efree((char *) MY_IO_ITEM);
  1896.         MY_IO_ITEM = NULL;
  1897.         cur_stackptr -= 3;
  1898.         PUSH(0);                 
  1899.         break;
  1900.     case ENDRDV_EVENT: 
  1901.         disable_io(&MY_IO_ITEM);
  1902.         if (MY_EXCEPTION)
  1903.             raise(MY_EXCEPTION, "Exception propagated from called task");
  1904.         MY_EXCEPTION = 0;
  1905.         for (i = cur_stackptr - num_param - 3 + 1; i <= cur_stackptr; i++)
  1906.             cur_stack[i] = cur_stack[i+3];
  1907.         cur_stackptr -=3;
  1908.         if (MY_STATUS == TIMED_RDV) 
  1909.             PUSH(1); 
  1910.         break;
  1911.     case TASKERR_EVENT :
  1912.         raise(TASKING_ERROR, "Entry call failed: called task terminated");
  1913.         MY_EXCEPTION = 0;             
  1914.         break;
  1915.     default    : 
  1916.         raise(SYSTEM_ERROR, "Unexpected event in entry call");     
  1917.         break;
  1918.     }
  1919.     MY_STATUS = ACTIVE;
  1920. }
  1921.  
  1922.  
  1923. /*-----------------------------------------------------------------------*/
  1924. /*                       U T I L I T Y    R O U T I N E S                */
  1925. /*-----------------------------------------------------------------------*/
  1926.  
  1927. /*--------------------------------------------------------------------------*/
  1928. /*                          ENTRY  QUEUE  ROUTINES                          */
  1929. /*   The following four routines (einit, eremove, eput & eget) are parallel */
  1930. /*   access queue routines for maintaining the entry queue in tasks' tcbs.  */
  1931. /*--------------------------------------------------------------------------*/
  1932.  
  1933. static void einit(struct entry_type    *entry)                            /*;einit*/
  1934. {
  1935.     ENTRY_LAST(entry) = NULL;
  1936.     ENTRY_FIRST(entry) = NULL;
  1937.     (LOCK(entry)).add_lock = 0;
  1938.     (LOCK(entry)).del_lock = 0;
  1939.     ENTRY_GUARD(entry) = 0;
  1940.     ENTRY_COUNT(entry) = 0;
  1941. }
  1942.  
  1943. static int eremove(int task)                                    /*;eremove*/
  1944. {
  1945.     if ((TCB_ENTRY_ITEM(task) == NULL) || (TCB_CURR_ENTRY(task) == NULL))
  1946.         return FALSE;
  1947.  
  1948.     add_lock(&(LOCK(TCB_CURR_ENTRY(task))));
  1949.     if (FAS(&(ITEM_FLAG(TCB_ENTRY_ITEM(task))), 0) == 0) {
  1950.         add_unlock(&(LOCK(TCB_CURR_ENTRY(task))));
  1951.         return FALSE;
  1952.     }
  1953.     else {
  1954.         DEC(ENTRY_COUNT(TCB_CURR_ENTRY(task)));
  1955.         add_unlock(&(LOCK(TCB_CURR_ENTRY(task))));
  1956.         TCB_CURR_ENTRY(task) = NULL;
  1957.         TCB_ENTRY_ITEM(task) = NULL;
  1958.         return TRUE;
  1959.     }
  1960. }
  1961.  
  1962. static void eput(struct entry_type *entry, int caller, struct q_item **ret_item)
  1963.                                                                     /*;eput*/
  1964. {
  1965.     struct q_item    *prev_item, *item;
  1966.  
  1967.     item = (struct q_item*) malloc(sizeof(struct q_item));
  1968.     if (item == (struct q_item*)0) {
  1969.         raise(STORAGE_ERROR, "Allocating space for entry queue");
  1970.         return;
  1971.     }
  1972.     ITEM_FLAG(item) = 1;
  1973.     ITEM_TASK(item) = caller;
  1974.     ITEM_NEXT(item) = NULL;
  1975.     prev_item =  FAS_Q(&(ENTRY_LAST(entry)), item);
  1976.     if (prev_item == (struct q_item *)0)
  1977.         FAS_Q(&(ENTRY_FIRST(entry)), item);
  1978.     else
  1979.         FAS_Q(&(ITEM_NEXT(prev_item)), item);
  1980.     *ret_item = item;
  1981. }
  1982.  
  1983. static int eget(struct entry_type *entry)                            /*;eget*/
  1984. {
  1985.     struct q_item        *caller, *new_caller;
  1986.     int            task;
  1987.  
  1988.     del_lock(&(LOCK(entry)));
  1989.     if (ENTRY_FIRST(entry) == NULL) {
  1990.         del_unlock(&(LOCK(entry)));
  1991.         return NULL_TASK;
  1992.     }
  1993.  
  1994.     ENTRY_GUARD(entry) = 0;
  1995.     caller = FAS_Q(&(ENTRY_FIRST(entry)), (ITEM_NEXT(ENTRY_FIRST(entry))));
  1996.     while ((caller != (struct q_item*)0) && (FAS(&(ITEM_FLAG(caller)),0) == 0)){
  1997.         new_caller = FAS_Q(&(ENTRY_FIRST(entry)),ITEM_NEXT(ENTRY_FIRST(entry)));
  1998.         efree((char *) caller);
  1999.         caller = new_caller;
  2000.     }
  2001.  
  2002.     if (caller != (struct q_item*)0) {
  2003.         if (TCB_IO_ITEM(ITEM_TASK(caller)) != NULL)
  2004.             disable_io(&(TCB_IO_ITEM(ITEM_TASK(caller))));
  2005.         if (ENTRY_COUNT(entry) == 0) FAS_Q(&(ENTRY_LAST(entry)), NULL);
  2006.         task = ITEM_TASK(caller);
  2007.         efree((char *) caller);
  2008.         TCB_ENTRY_ITEM(task) = (struct q_item *)0;
  2009.     }
  2010.     else task = NULL_TASK;
  2011.     del_unlock(&(LOCK(entry)));
  2012.     return(task);
  2013. }
  2014.  
  2015. /*---------------------------------------------------------------------------*
  2016.  *                           LOCKING  ROUTINES                               *
  2017.  *                                                                           *
  2018.  * Locks on entries may be either "add" locks or "del" locks.  "del" (or     *
  2019.  * delete) locks have precedence over "add" locks.  These are implemented    *
  2020.  * using a standard A-B locking scheme.                                      *
  2021.  *---------------------------------------------------------------------------*/
  2022.  
  2023. static void add_lock(struct lock_type *lock)                    /*;add_lock*/
  2024. {
  2025.     for (;;) {
  2026.         while (lock->del_lock > 1) continue;  /* wait for dels to end */
  2027.         INC(lock->add_lock);             /* try tp get add lock  */
  2028.         if (lock->del_lock > 1)               /* oops, del started... */
  2029.             DEC(lock->add_lock);
  2030.         else break;
  2031.     }
  2032. }
  2033.  
  2034. static void add_unlock(struct lock_type *lock)                    /*;add_unlock*/
  2035. {
  2036.     DEC(lock->add_lock);
  2037. }
  2038.  
  2039. static void del_lock(struct lock_type *lock)                    /*;del_lock */
  2040. {
  2041.     INC(lock->del_lock);         /* don't allow adds to start */
  2042.     while (lock->add_lock > 1) continue;  /* wait for adds to end */
  2043. }
  2044.  
  2045. static void del_unlock(struct lock_type *lock)                    /*;del_unlock*/
  2046. {
  2047.     DEC(lock->del_lock);
  2048. }
  2049.  
  2050. /*-----------------------------------------------------------------------*/
  2051. /*                          ENTRY NUMBER                                 */
  2052. /*-----------------------------------------------------------------------*/
  2053.  
  2054. static int entry_number(int owner, int family, int member)    /*;entry_number*/
  2055. {
  2056.     return (*ADDR(TCB_TBASE(owner), TCB_TOFF(owner) + 2 * (family -1))
  2057.       + member + 1);
  2058. }
  2059.  
  2060. /*------------------------------------------------------------------------*
  2061.  *                          RAISE  IN  CALLER                             *
  2062.  * Procedure to raise an exception in the task waiting for the completion *
  2063.  * of the current rendezvous                          *
  2064.  * -----------------------------------------------------------------------*/
  2065.  
  2066. void raise_in_caller()                                    /*;raise_in_caller*/
  2067. {
  2068. #ifdef TRACE
  2069.     if (exception_trace)
  2070.         printf("task %d raising exception %s in task %d\n",tp,
  2071.           exception_slots[exr],MY_SERVICED);
  2072. #endif
  2073.     TCB_EXCEPTION(MY_SERVICED) = exr;
  2074. }
  2075.  
  2076.  
  2077. /* -----------------------------------------------------------------------*
  2078.  *                           ATTRIBUTE  ROUTINES                          *
  2079.  *  The following three routines (is_callable, is_terminated and count)   *
  2080.  *  return the attributes 'CALLABLE, 'TERMINATED and 'COUNT respecitvely  *
  2081.  *  for the given task                                                    *
  2082.  * -----------------------------------------------------------------------*/
  2083.  
  2084. int is_callable(int task)                                    /*;is_callable*/
  2085. {
  2086.     if (task != ORIG(task) || STACK(task) == (int *)0 || TCB_ABNORMAL(task))
  2087.         return FALSE;
  2088.     switch(TCB_STATUS(task)) {
  2089.     case TERMINATED:
  2090.     case ABNORMAL: 
  2091.         return FALSE;
  2092.     case COMPLETED:     /* are we completed on the last level? */
  2093.         return BF_PREVIOUS_BFP(task, *(TCB_BLOCK_PTR(task))) == NULL_TASK;
  2094.     default: 
  2095.         return TRUE;
  2096.     }
  2097. }
  2098.  
  2099. int is_terminated(int task)                                /*;is_terminated*/
  2100. {
  2101.     if (task != ORIG(task) || STACK(task) == (int *)0 )  return TRUE;
  2102.     return (TCB_STATUS(task) == TERMINATED);
  2103. }
  2104.  
  2105. int count(int family, int member)                                /*;count*/
  2106. {
  2107.     return(ENTRY_COUNT(MY_ENTRY(entry_number(tp, family, member))));
  2108. }
  2109.  
  2110. /*---------------------------------------------------------------------------*/
  2111. /*                              MULTISIGNAL                                  */
  2112. /*---------------------------------------------------------------------------*/
  2113.  
  2114. static void multisignal(int task, int event)                 /*;multisignal*/
  2115. {
  2116.     if (event != NO_EVENT) TCB_EVENT(task) = event;
  2117.     if (DEC(TCB_NUM_ITEMS(task)) == 1)
  2118.         make_ready(task, NO_EVENT);
  2119. }
  2120.  
  2121. /*---------------------------------------------------------------------------*/
  2122. /*                            "SERVICED"  QUEUE                              */
  2123. /*---------------------------------------------------------------------------*/
  2124.  
  2125. static void add_serviced(int server, int task)                /*;add_serviced*/
  2126. {
  2127.     TCB_NEXT(task) = FAS(&(TCB_SERVICED(server)), task);
  2128. }
  2129.  
  2130. static int remove_serviced()                            /*;remove_serviced*/
  2131. {
  2132.     return(FAS(&(MY_SERVICED), TCB_NEXT(MY_SERVICED)));
  2133. }
  2134.  
  2135. /*--------------------------------------------------------------------------*/
  2136. /*                             READY  QUEUE                                 */
  2137. /*  The following three routines (qinit, enqueue, enqueue_item and dequeue) */
  2138. /*  are the routines used in accessing the ready queue.  The other three    */
  2139. /*  routines are used to control the scheduler.                             */
  2140. /*--------------------------------------------------------------------------*/
  2141.  
  2142. static void qinit()                                                    /*;qinit*/
  2143. {
  2144.     int    i;
  2145.     struct ready_q    *q;
  2146.  
  2147.     for (i = 0; i < MAX_PRIO; i++) {
  2148.         ready_queue[i] = (struct ready_q *)malloc(sizeof(struct ready_q));
  2149.         q = ready_queue[i];
  2150.         if (q == (struct ready_q *)0) {
  2151. #ifdef vms
  2152.             LIB$STOP(MSG_NOSTACK);
  2153. #else
  2154.             printf("Unable to allocate stack\n");
  2155.             exit(RC_ABORT);
  2156. #endif
  2157.         }
  2158.         q->first = NULL;
  2159.         q->last = NULL;
  2160.         q->first_mult = 0;
  2161.         q->count = 0;
  2162.         q->lock.add_lock = 0;
  2163.         q->lock.del_lock = 0;
  2164.     }
  2165. }
  2166.  
  2167. static void enqueue(int priority, int value)                    /*;enqueue*/
  2168. {
  2169.     struct rts_item    *item;
  2170.  
  2171.     item = (struct rts_item *) malloc(sizeof(struct rts_item));
  2172.     if (item == (struct rts_item *)0){
  2173.         raise(STORAGE_ERROR, "Allocating space for ready queue");
  2174.         return;
  2175.     }
  2176.     item->tcbs = (int *) malloc(sizeof(int));
  2177.     if (item->tcbs == (int *)0){
  2178.         raise(STORAGE_ERROR, "Allocating space for ready queue");
  2179.         return;
  2180.     }
  2181.     RTS_TYPE(item) = READY;
  2182.     RTS_PRIO(item) = priority;
  2183.     RTS_MULT(item) = 1;
  2184.     RTS_NEXT(item) = NULL;
  2185.     RTS_TCBS(item, 0) = value;
  2186.     enqueue_item(priority, item);
  2187. }
  2188.  
  2189. static void enqueue_item(int priority, struct rts_item *item)  /*;enqueue_item*/
  2190. {
  2191.     struct ready_q    *q;
  2192.     struct rts_item    *prev;
  2193.  
  2194.     RTS_SAVE_MULT(item) = RTS_MULT(item);
  2195.     q = ready_queue[priority];
  2196.     while (highest_priority < priority)
  2197.         priority = FAS(&highest_priority, priority);
  2198.     add_lock(&(LOCK(q)));
  2199.     prev = FAS_RTS(&(q->last), item);
  2200.     if (prev == (struct rts_item *)0) {
  2201.         FAS_RTS(&(q->first), item);
  2202.         FAS(&(q->first_mult), item->mult);
  2203.     }
  2204.     else    FAS_RTS(&(prev->next), item);
  2205.     q->count += item->mult;
  2206.     add_unlock(&(LOCK(q)));
  2207. }
  2208.  
  2209. static struct rts_item *dequeue(struct ready_q *q, int *i)            /*;dequeue*/
  2210. {
  2211.     struct rts_item    *item;
  2212.     int    j, k;
  2213.  
  2214.     if (q->count <= 0) return (struct rts_item *)0;
  2215.     else if (DEC(q->count) < 1) {
  2216.         INC(q->count);
  2217.         return (struct rts_item *)0;
  2218.     }
  2219.     else {
  2220.         while (q->first_mult > 0 && DEC(q->first_mult) < 1) continue;
  2221.         item = q->first;
  2222.         if ((j = DEC(q->first->mult)) == 1) {  /* remove from list */
  2223.             RTS_MULT(q->first) = RTS_SAVE_MULT(q->first);
  2224.             if (q->first->next == NULL)  {
  2225.                 del_lock(&(LOCK(q)));
  2226.                 if (q->first->next == NULL)  {
  2227.                     FAS_RTS(&q->first, NULL);
  2228.                     FAS_RTS(&q->last, NULL);
  2229.                 }
  2230.                 else {
  2231.                     FAS_RTS(&(q->first), q->first->next);
  2232.                     FAS(&(q->first_mult), q->first->mult);
  2233.                 }
  2234.                 del_unlock(&(LOCK(q)));
  2235.             }
  2236.             else {
  2237.                 FAS_RTS(&(q->first), q->first->next);
  2238.                 FAS(&(q->first_mult), q->first->mult);
  2239.             }
  2240.         }
  2241.         k = 0; 
  2242.         *i = -1;
  2243.         while (k < j)
  2244.             if (item->tcbs[++(*i)] != NULL_TASK) k++;
  2245.         return item;
  2246.     }
  2247. }
  2248.  
  2249. static void context_switch()                                /*;context_switch*/
  2250. {
  2251.     DEC(MY_NUM_EVENTS);
  2252.     make_ready(tp, TIMER_EVENT);
  2253.     schedule(CONTEXT_SWITCH);
  2254. }
  2255.  
  2256. #ifdef IBM_PC
  2257. static void sleep(unsigned secs)
  2258. {
  2259.     clock_t check = clock();
  2260.     check += secs * CLOCKS_PER_SEC;
  2261.     while (clock() < check)
  2262.         ;
  2263. }
  2264. #endif
  2265.