IMPLEMENTATION MODULE RoundRobinScheduler;

(** ------------------------------------------------------------------

              Commodore Amiga round robin scheduler module

      (c) Copyright 1986 Modula-2 Software Ltd.  All Rights Reserved
      (c) Copyright 1986 TDI Software, Inc.      All Rights Reserved

    ------------------------------------------------------------------ **)


(* VERSION FOR COMMODORE AMIGA

     Original Author : Modula-2 Software Ltd.

     Version         : 1.11a  23-Jan-86  Paul Curtis, Modula-2 Software Ltd.
                         Version for Amiga.
                       1.10a   03-Jul-85   Phil Camp, Modula-2 Software Ltd.,
                         Changed stupid names.
                         Made Initialise dispose old tasks.
                         Added security to NextTask proc if not tasking.
                         Upped stack size for task.

  *)


(*$S-,$T-,$Q+*)


FROM SYSTEM IMPORT PROCESS, NEWPROCESS, TRANSFER, ADR; 
FROM Storage IMPORT ALLOCATE, DEALLOCATE;


CONST ProcessSize = 2048;


TYPE
  Task = POINTER TO TaskRecord;
  TaskRecord = RECORD
                 process: PROCESS;
                 next: Task;
                 processspace: ARRAY [0..ProcessSize-1] OF CARDINAL;
               END;

      
VAR 
  OldTask, NewTask, FirstTask, LastTask: Task;
  ProgramProcess: PROCESS;
  Tasking: BOOLEAN; (* Tasks in progress *)   (*1.10a*)


PROCEDURE InitialiseScheduler;
  (* Initialise tasks *)
VAR
  tempTask: Task;
BEGIN
  IF LastTask # NIL THEN
    LastTask^.next := NIL;     (* cut circle of tasks *)
    LastTask := NIL;
  END;
  WHILE FirstTask # NIL DO
    tempTask := FirstTask^.next;
    DISPOSE(FirstTask);
    FirstTask := tempTask;
  END;
END InitialiseScheduler;


PROCEDURE CreateTask(proc: PROC);
  (* Allocate space for a process, and link into ready list *)
VAR 
  newtask: Task;
BEGIN
  NEW(newtask); (* Allocate the task workspace on the Heap *)
  newtask^.next := NIL;
  NEWPROCESS(proc,ADR(newtask^.processspace),ProcessSize,newtask^.process);
  IF FirstTask = NIL THEN
    FirstTask := newtask;
  ELSE
    LastTask^.next := newtask;
  END;
  LastTask := newtask;
END CreateTask;


PROCEDURE StartSchedulingTasks;
  (* Transfers control from program 'process' to the new task *)
BEGIN
  LastTask^.next := FirstTask;    (* Link first and last tasks *)
  NewTask := FirstTask;
  Tasking := TRUE ;                                            (*1.10a*)
  TRANSFER(ProgramProcess,NewTask^.process);
END StartSchedulingTasks;


PROCEDURE StopSchedulingTasks;
  (* Transfers control from the old task back to the program 'process' *)
BEGIN
  Tasking := FALSE;                                           (*1.10a*)
  TRANSFER (OldTask^.process,ProgramProcess);
END StopSchedulingTasks;


PROCEDURE NextTask;
  (* Change new task to old task, transfer to next new task on list *)
  (* Checks if any tasks active *)                          (*1.10a*)
BEGIN
  IF Tasking THEN                                              (*1.10a*)
    OldTask := NewTask; (* Set up the task pointers *)
    NewTask := NewTask^.next;
         
    (* Transfer control to next task *)
    TRANSFER(OldTask^.process,NewTask^.process);
  END;
END NextTask;


BEGIN
  Tasking := FALSE;                                            (*1.10a*)
  FirstTask := NIL;
  LastTask := NIL;
END RoundRobinScheduler.
