MODULE Task; (* SJ *)

(* Task is used to divide programs into tasks. A task is a part of a
   program that works separatly (allocates its own memory, opens windows
   etc), and leaves everything in the state it was before the task.
   Moule Task simplifies this : just call Task.Init before starting the
   task and Task.Exit after finishing the task. This will automatically
   free the memory allocated inbetween, close the windows etc. This is
   accomplished by storing and calling procedures of modules, which do
   these things (Storage, Wind etc.). Task also installes a procedure
   in System.Halt which outputs a message via Form.Alert and terminates
   the current task via Exit. A special handling is implemented for the
   ACCLOSE message. This message is send to accessories AFTER having
   deallocated its memory, closed its windows etc. (VDI workstations
   are not affected !). This means that for example Storage is not allowed
   to free its memory on an ACCLOSE message. Therefore the procedure
   AcClose was implemented. It sets the variable Closed to TRUE and
   calls all stored exit procedures and decrements Current until it is 0.
   Task 0 is not allowed to allocate memory or other critical things.
   Program execution is continued in the base process which should call
   an event routine to wait for ACOPEN. If Exit is called when Current is
   0, program execution is terminated by calling GEMDOS.Pterm(RetCode).
   Example : call of the compiler :

   PROCEDURE CallCompiler(Name : ARRAY OF CHAR);
    BEGIN
     Task.Init; Compile(Name); Task.Exit; (* all memory deallocated *)
     (* all commands after Task.Exit are not executed because Task.Exit
        terminates the task procedure *)
    END CallCompiler;
*)


TYPE proc* = PROCEDURE;


VAR Current*: INTEGER; 

(* current process number, incremented by Init, decremented by Exit *)

VAR RetCode*: INTEGER; (* this value is returned to GEMDOS on exit *)


VAR FreeMem*: proc;

(* Storage links a procedure to free the memory allocated by the terminated 
   process. This can't be done via StoreExit because the memory must be 
   freed after the other exit procedures have been called *)


VAR Closed* : BOOLEAN; 

(* normally FALSE. Set to TRUE if AcClose is called to indicate that memory 
   is already deallocated etc.
*)


PROCEDURE StoreInit*(Init : proc);

 (* stores a procedure to be called if Init is called *)


PROCEDURE Init*;

 (* initiate a task. Current is incremented and all procedures stored
    with StoreInit are called *)


PROCEDURE StoreExit*(Exit : proc);

 (* stores a procedure to be called if Exit is called *)


PROCEDURE Exit*;

 (* terminate a task. All procedures stored with StoreExit are called
    and Current is decremented. Program execution is continued in the
    procedure that called the task procedure in which Init was called *)


PROCEDURE AcClose*;

 (* terminates all tasks except the base task with Closed set to TRUE.
    See documentation above *)


PROCEDURE Quit*;

  (* terminates program run *)


END Task.
