Listing 2

/*

  fork_driver(routine, param)
  void (*routine)();
  unsigned long param;

  This routine places the passed routine onto the fork
  queue. The driver is allowed to pass up to four bytes
  to the target routine.

  The driver's action is considered complete, and it will
  not be reentered until another interrupt occurs.

*/

void fork_driver(routine, param)
void (*routine)();
unsigned long param;
  {
  FORK_PARAM *current_fork;
  DSS *current_dcb;
  unsigned chat current_name[NAME_SIZE + 1];

  /* Get address of driver's TSS. */
  current_dcb = get_tss(NULL);

  /* Make sure we are allowed to fork this device again. */
  if (current_dcb -> current_fork_count >= current_dcb ->
     max_fork_count && current_dcb -> max_fork_count)
    {
    /* Can't fork another entry on this device. Throw
      away interrupt. (Serious Problem Here!)           */
    if (in_executive || fork_in_process)
      resume_last();
    else
      resume(scheduler_task);
    return;
    }

/* Get next entry. */
if (!(current_fork = fork_free))
  {
  /* Out of fork space. Throw away interrupt.
     (Serious Problem Here!)             */
  if (in_executive || fork_in_process)
    resume_last();
  else
    resume(scheduler_task);
  return;
  }

/* Get the next free fork queue entry link */
fork_free = fork_free -> link;

/* Fill the entry with the address of the driver's TSS,
   the interrupt-enabled routine address, the passed
   parameter, and clear the link.         */

current_fork -> tcb = current_dcb;
current_fork -> routine = routine;
current_fork -> param1 = param;
current_fork -> link = NULL;

/* Add one to the count of fork entries for this
  device.                        */

++current_dcb -> current_fork_count;

/* Link it onto the end of the fork queue */
if (fork_queue)
  fork_queue_tail = fork_queue_tail -> link = current_fork;

else
  fork_queue = fork_queue_tail = current_fork;

/* If in a system service call, or currently executing
   the fork, resume what we were last doing. Otherwise
   else start up the fork queue.           */

if (in_executive || fork_in_process)
  resume_last();
else
  resume(fork_queue_task);
}