DEFINITION MODULE ATOMIC;       (* Copyright 1987 fred brooks LogicTek *)
(* V1.0 *)
FROM    SYSTEM  IMPORT  PROCESS,ADDRESS;
FROM    Strings IMPORT  String;

CONST   MAGIC   = 92957; (* my b-day *)

TYPE            SIGNAL          =       POINTER TO ProcessDescriptor;
                GEMTYPE         =       ARRAY [0..0ffH] OF ADDRESS;

(* This is the control record for all system process. Variable
   "currentprocess" points to the currently running process. The ready
   queue is implemented as a linked list round robin. *)

(* The gemsave array contains important system vectors that are switched
   with every process. This allows programs to intercept trap vectors
   such as the GEMDOS TRAP 1 and still to allow the other programs
   to run correctly.       current vectors saved are
                           gemsave[0]      gem workspace pointer
                           gemsave[1]      LINEA   VECTOR    28H
                           gemsave[2]      GEMDOS  TRAP 1    84H
                           gemsave[3]      GSX,GEM TRAP 2    88H
                           gemsave[4]      BIOS    TRAP 13   B4H
                           gemsave[5]      XBIOS   TRAP 14   B8H
                           gemsave[6]      linef   VECTOR    2CH
                           gemsave[7]      level2  VECTOR    68H
                           gemsave[8]      level4  VECTOR    70H
*)

        ProcessDescriptor =
               RECORD
                        name    :       String;   (* process name *)
                        pid     :       INTEGER;  (* process id   *)
                        cor     :       PROCESS;  (* process coroutine *)
                        pc      :       ADDRESS;  (* process PC *)
                        sr      :       CARDINAL; (* process SR *)
                        ssp     :       ADDRESS;  (* process super SR *)
                        biosval :       ADDRESS;  (* bios call save ptr *)
                        retval  :       ADDRESS;
                        biosave :       ARRAY [0..199] OF CARDINAL;
                        gemsave :       ARRAY [0..15]  OF ADDRESS; 
                        termvec :       ADDRESS;
                        wsp     :       ADDRESS;  (* process work space *)
                        wspsize :       LONGCARD; (* size of work space *)
                        next    :       SIGNAL;   (* ptr to next process *)
                        ppid    :       INTEGER;  (* parent id *)
                        tmpcor  :       PROCESS;  (* cor save variable *)
                        ready   :       BOOLEAN;  (* process run flag *)
                        active  :       BOOLEAN;  (* process alive flag *)
                        intflag :       BOOLEAN;  (* process switched *)
                        date    :       CARDINAL; (* date started *)
                        time    :       CARDINAL; (* time started *)
                        tick    :       LONGCARD; (* total 200hz clocks *)
                        slice   :       LONGCARD; (* restart time 200hz *)
                        pri     :       INTEGER;  (* set length of run *)
                        flags   :       ARRAY [0..2] OF LONGCARD; (* var *)
                        ipname  :       String;   (* program name *)
                        iptail  :       String;   (* program command *)
                      ipenvstr  :       String;   (* program env string *)
                        return  :       INTEGER;  (* function return *)
                        errno   :       INTEGER;  (* error number *)
                        bpsave  :       GEMTYPE;  (* save for gemdos *)
               END;

(* Vector 144H points to variable that contains this record *)
(* look at SYS.MOD for an example of use of these variables *)

     sysrequesttype =
               RECORD
                  req         : BOOLEAN;
                  pid         : INTEGER;
                  magic       : LONGCARD;
               END;

     spinttype =
               RECORD
                  proc        : PROC;
                  pid         : INTEGER;
                  data        : ADDRESS;
               END;

        sysvariable =
               RECORD
                  currentprocess  : POINTER TO SIGNAL;
                  MULTI           : POINTER TO BOOLEAN;
                  slicebegin      : POINTER TO LONGCARD;
                  contextswitch   : POINTER TO LONGCARD;
                  command         : POINTER TO String;
                  request         : POINTER TO sysrequesttype;
                  CRON            : POINTER TO PROC;
                  spintenable     : POINTER TO BITSET;
                  spintmask       : POINTER TO BITSET;
                  spint           : POINTER TO ARRAY [0..15] OF spinttype;
                  bpsave          : POINTER TO GEMTYPE;
               END;

VAR             currentprocess               : SIGNAL;
                MULTI                        : BOOLEAN;
                slicebegin                   : LONGCARD;
                contextswitch                : LONGCARD;
                command                      : String;
                request                      : sysrequesttype;
                CRON                         : PROC;
                spintenable                  : BITSET;
                spintmask                    : BITSET;
                spint                        : ARRAY [0..15] OF spinttype;
                bpsave                       : GEMTYPE;
                (* A spint is a software interrupt. It is called by
                   setting it's bit in the spint enable mask.    *)
                (* The CRON procedure variable is here to put your
                   own procedure into the init scheduler in AMULTI this
                   procedure will be run every 60 seconds. It is setup to
                   the dummy procedure at first. to setup your own
                   get sysvar then (sysvar.CRON:='your procedure') *)

(* start the master context switch interrupt and setup system variables *)
PROCEDURE Initsked;

(* setup kernal to begin the system startup setup all buffers and 
   procedures for AMULTI *)
PROCEDURE InitProcesses;

(* shutdown kernal and restore to normal gem state *)
PROCEDURE EndProcesses;

(* create a process for the AMULTI system, place in the scheduler ready
   list, start new process *)
PROCEDURE StartProcess(VAR P: PROC; 
                       VAR n: LONGCARD; 
                       VAR priority: INTEGER; 
                       VAR pn: String);

(* store the currentprocess and switch to next process in ready list *)
PROCEDURE SwapProcess;

(* end process and remove it from the ready list, free memory used by
   process *)
PROCEDURE TermProcess(VAR id: INTEGER);

(* tell scheduler not to run this process but keep in memory *)
PROCEDURE SleepProcess(VAR id: INTEGER);

(* tell scheduler to start running this process again if it was sleeping
   before *)
PROCEDURE WakeupProcess(VAR id: INTEGER);

(* V0.7 change process priority *)
PROCEDURE ChangeProcessPriority(VAR id: INTEGER; VAR pri: INTEGER);

(* turn on the scheduler interrupt, and start normal process switching *)
PROCEDURE MultiBegin;

(* turn off the scheduler interrupt, used to stop process switching in
   section of code that should not be swapped out *)
PROCEDURE MultiEnd;

(* check if flag is TRUE and lock out other process from changing it's
   state until procedure is over *)
PROCEDURE CheckFlag(VAR flag: BOOLEAN): BOOLEAN;

(* set flag to TRUE and lock out other process from changing it's
   state until procedure is over *)
PROCEDURE SetFlag(VAR flag: BOOLEAN);

(* set flag to FALSE and lock out other process from changing it's
   state until procedure is over *)
PROCEDURE ResetFlag(VAR flag: BOOLEAN);

(* check if flag is TRUE then set flag to FALSE while locking out other 
   process from changing it's state until procedure is over *)
PROCEDURE CheckResetFlag(VAR flag: BOOLEAN): BOOLEAN;

END             ATOMIC.
