DEFINITION MODULE TaskControl;

        (****************************************************************)
        (*                                                              *)
        (*   Data structures internal to the kernel of the operating    *)
        (*     system; the dispatcher of the operating system; and      *)
        (*                  related procedures.                         *)
        (*                                                              *)
        (*      Programmer:     P. Moylan                               *)
        (*      Last edited:    17 August 2020                          *)
        (*      Status:         OK                                      *)
        (*                                                              *)
        (****************************************************************)

FROM SYSTEM IMPORT ADDRESS;
FROM OS2 IMPORT HMTX;

(************************************************************************)
(*                                                                      *)
(*                         END-USER PROCEDURES                          *)
(*                                                                      *)
(************************************************************************)

CONST MaxPriority = 159;

    (* NOTE: an OS/2 thread has a priority class with values    *)
    (*      0   null task (?)                                   *)
    (*      1   idle                                            *)
    (*      2   regular                                         *)
    (*      3   time critical                                   *)
    (*      4   server                                          *)
    (* and a priority within the class in the range -31..+31.   *)
    (* The XDS processes module encodes this as                 *)
    (*   urgency = 32*class + (priority within class)           *)
    (* giving a maximum value of 4*32+31 = 159 because it makes *)
    (* no provision for a negative priority within class 0.     *)
    (* A different encoding is used inside the tib2 thread      *)
    (* information block, where the class is stored in the high *)
    (* byte of the priority value.                              *)

TYPE
    PriorityLevel = [0..MaxPriority];
    NameString = ARRAY [0..15] OF CHAR;
    PROC1 = PROCEDURE (ADDRESS);


PROCEDURE IsFullScreen(): BOOLEAN;

    (* Returns TRUE if this is a full-screen OS/2 session. *)

PROCEDURE NotDetached(): BOOLEAN;

    (* Returns TRUE unless called by a process running detached.        *)
    (* (A detached process may not do keyboard, screen, or mouse I/O.)  *)

PROCEDURE CreateTask (StartAddress: PROC;  taskpriority: PriorityLevel;
                                           taskname: NameString): BOOLEAN;

    (* Must be called to introduce a task to the system. The first      *)
    (* parameter, which should be the name of a procedure containing    *)
    (* the task code, gives the starting address.  The second parameter *)
    (* is the task's base priority.  If this task has a higher priority *)
    (* than its creator, it will run immediately.  Otherwise, it        *)
    (* becomes ready.                                                   *)

    (* A task terminates itself either by an explicit call to TaskExit, *)
    (* or simply by falling out of the bottom of its code.              *)
    (* There is no provision for tasks to kill other tasks.  Suicide    *)
    (* is legal, but murder is not.                                     *)

    (* The TaskPriority value should be OS-independent, but in practice *)
    (* it is not. For OS/2 the values are:                              *)
    (*                                                                  *)
    (*      taskpriority   Priority class                               *)
    (*                                                                  *)
    (*      -32 - -1        PRTYC_IDLETIME                              *)
    (*        0 - 31        PRTYC_REGULAR                               *)
    (*       32 - 63        PRTYC_TIMECRITICAL                          *)
    (*       64 - 95        PRTYC_FOREGROUNDSERVER                      *)
    (*                                                                  *)
    (* NOTE: this might be obsolete information from an earlier version *)
    (* of XDS Modula-2.  See earlier in this file for the values that   *)
    (* I found from test.                                               *)

PROCEDURE CreateTask1 (StartAddress: PROC1;  taskpriority: PriorityLevel;
                          taskname: NameString;  param: ADDRESS): BOOLEAN;

    (* Like CreateTask, but allows the passing of a single parameter    *)
    (* "param" to the task.                                             *)

(*
PROCEDURE CreateTaskSpecial (StartAddress: PROC;  taskpriority: PriorityLevel;
                                           taskname: NameString): BOOLEAN;
*)
    (* Like CreateTask, but starts the task with a direct API call      *)
    (* rather than going through module Processes.  (This is not a      *)
    (* good long-term solution, I'm using it only for a few special     *)
    (* tests.)                                                          *)

PROCEDURE TaskExit;

    (* Removes the currently running task from the system, and performs *)
    (* a task switch to the next ready task.                            *)

    (* There is normally no need for a task to call this procedure,     *)
    (* because it is automatically called when the task code "falls out *)
    (* the bottom" by executing its final procedure return.             *)

PROCEDURE ThreadCount(): CARDINAL;

    (* Returns the number of currently running threads. *)

PROCEDURE Crash (message: ARRAY OF CHAR);

    (* Aborts the program in a way that will let us do a postmortem check. *)

(************************************************************************)
(*                                                                      *)
(*                LOCKS FOR CRITICAL SECTION PROTECTION                 *)
(*                                                                      *)
(*  Note that we distinguish between a Lock and a Semaphore.            *)
(*  A Semaphore is a general semaphore - whose operations are defined   *)
(*  in module Semaphores - which can be used for general inter-task     *)
(*  interlocking.  A Lock is similar to a binary semaphore (with a      *)
(*  more efficient implementation than a Semaphore), but may be used    *)
(*  only in a strictly nested fashion and is therefore useful only      *)
(*  for critical section protection.                                    *)
(*                                                                      *)
(************************************************************************)

TYPE Lock = HMTX;

PROCEDURE CreateLock (VAR (*OUT*) L: Lock);

    (* Creates a new lock. *)

PROCEDURE DestroyLock (VAR (*INOUT*) L: Lock);

    (* Disposes of a lock. *)

PROCEDURE Obtain (L: Lock);

    (* Obtains lock L, waiting if necessary. *)

PROCEDURE Release (L: Lock);

    (* Releases lock L - which might unblock some other task. *)

(************************************************************************)
(*                  PROCEDURES PRIVATE TO THE KERNEL                    *)
(************************************************************************)

TYPE TaskID = CARDINAL;

PROCEDURE CurrentTaskID(): TaskID;

    (* Returns the TaskID of the calling task. *)

PROCEDURE SuspendMe (id: TaskID;  TimeLimit: CARDINAL): BOOLEAN;

    (* Suspends the caller.  A TRUE result indicates that the time      *)
    (* limit expired without the task being woken up.                   *)

PROCEDURE ResumeTask (id: TaskID): BOOLEAN;

    (* Resumes a task specified by its thread ID.                       *)
    (* The function result is normally TRUE, but is FALSE if the task   *)
    (* couldn't be resumed (usually because that task no longer exists).*)

END TaskControl.

