?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Operating System : System Task Management - Ring 3' ??
MODULE osm$system_task_maint_23d;

{ PURPOSE:
{   This module contains the procedures that manage the definition and execution of system tasks.
{
{   All procedures that access the system task execution table reside in this module.  The system task
{   execution table contains the task_id and task_status variable for each executing system tasks.
{   The task status variable cannot reside in the (ring 1) system task table since this variable is
{   written by (ring 3) task termination code.

?? NEWTITLE := 'Global Declarations Referenced by this Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc clt$parameter_list
*copyc jme$queued_file_conditions
*copyc loc$task_services_library_name
*copyc ofe$error_codes
*copyc ose$system_task_exceptions
*copyc oss$task_shared
*copyc ost$name
*copyc pmt$task_id
*copyc pmt$task_status
?? POP ??
*copyc avp$ring_min
*copyc avp$system_displays
*copyc avp$system_operator
*copyc clp$convert_string_to_file
*copyc clp$log_comment
*copyc clp$put_job_command_response
*copyc jmp$system_job
*copyc osp$activate_system_task_r1
*copyc osp$active_system_task_r1
*copyc osp$clear_job_signature_lock
*copyc osp$copy_local_status_to_status
*copyc osp$deactivate_system_task_r1
*copyc osp$define_system_task_r1
*copyc osp$delete_system_task_r1
*copyc osp$executing_in_job_monitor
*copyc osp$get_system_task_data_r1
*copyc osp$scan_system_task_table
*copyc osp$set_job_signature_lock
*copyc osp$set_status_abnormal
*copyc osp$store_system_task_status
*copyc osp$system_error
*copyc osv$task_shared_heap
*copyc pmp$execute_with_less_privilege
*copyc pmp$get_task_id
*copyc pmp$log
*copyc pmp$set_spy_identifier
*copyc pmp$terminate_task_without_wait
*copyc tmp$ready_system_task1
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by this Module', EJECT ??

  TYPE
    ost$system_task_execution_entry = record
      next_entry: ^ost$system_task_execution_entry,
      task_name: ost$name,
      task_id: pmt$task_id,
      task_status: pmt$task_status
    recend;

  VAR
    system_task_execution_lock: [oss$task_shared] ost$signature_lock := [0],
    system_task_execution_table: [oss$task_shared] ^ost$system_task_execution_entry := NIL;

?? OLDTITLE ??
?? NEWTITLE := 'convert_program_description', EJECT ??

{ PURPOSE:
{   The purpose of this request is to convert a program description from type llt$program_description
{   to type pmt$program_description.
{ NOTES:
{   The conversion consists of converting each file path name to a file path handle.
{
{   This request assumes that its caller has allocated a pmt$program_description of sufficient size to
{   contain the converted program description.

  PROCEDURE convert_program_description
    (    original_program_description: ^llt$program_description;
         converted_program_description: ^pmt$program_description;
     VAR status: ost$status);

    VAR
      enable_inhibit_conditions: ^pmt$enable_inhibit_conditions,
      file_index: 1 .. pmc$max_object_file_list,
      library_enable_inhib_conditions: ^pmt$enable_inhibit_conditions,
      library_index: 1 .. pmc$max_library_list,
      library_module_list: ^pmt$module_list,
      library_object_file_list: ^llt$object_file_list,
      library_object_library_list: ^llt$object_library_list,
      library_program_attributes: ^llt$program_attributes,
      library_program_description: ^llt$program_description,
      module_list: ^pmt$module_list,
      object_file_list: ^pmt$object_file_list,
      object_library_list: ^pmt$object_library_list,
      program_attributes: ^pmt$program_attributes,
      program_description: ^pmt$program_description,
      program_file: clt$file;

    status.normal := TRUE;
    library_program_description := original_program_description;
    RESET library_program_description;
    NEXT library_program_attributes IN library_program_description;
    program_description := converted_program_description;
    RESET program_description;
    NEXT program_attributes IN program_description;

    program_attributes^.contents := library_program_attributes^.contents;
    IF pmc$starting_proc_specified IN program_attributes^.contents THEN
      program_attributes^.starting_procedure := library_program_attributes^.starting_procedure;
    IFEND;

    IF pmc$object_file_list_specified IN program_attributes^.contents THEN
      program_attributes^.number_of_object_files := library_program_attributes^.number_of_object_files;
      NEXT library_object_file_list: [1 .. program_attributes^.number_of_object_files] IN
            library_program_description;
      NEXT object_file_list: [1 .. program_attributes^.number_of_object_files] IN program_description;
      FOR file_index := 1 TO program_attributes^.number_of_object_files DO
        clp$convert_string_to_file (library_object_file_list^ [file_index], program_file, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        object_file_list^ [file_index] := program_file.local_file_name;
      FOREND;
    IFEND;

    IF pmc$module_list_specified IN program_attributes^.contents THEN
      program_attributes^.number_of_modules := library_program_attributes^.number_of_modules;
      NEXT library_module_list: [1 .. program_attributes^.number_of_modules] IN library_program_description;
      NEXT module_list: [1 .. program_attributes^.number_of_modules] IN program_description;
      module_list^ := library_module_list^;
    IFEND;

    IF pmc$library_list_specified IN program_attributes^.contents THEN
      program_attributes^.number_of_libraries := library_program_attributes^.number_of_libraries;
      NEXT library_object_library_list: [1 .. program_attributes^.number_of_libraries] IN
            library_program_description;
      NEXT object_library_list: [1 .. program_attributes^.number_of_libraries] IN program_description;
      FOR library_index := 1 TO program_attributes^.number_of_libraries DO
        IF library_object_library_list^ [library_index] = loc$task_services_library_name THEN
          object_library_list^ [library_index] := loc$task_services_library_name;
        ELSE
          clp$convert_string_to_file (library_object_library_list^ [library_index], program_file, status);
          IF NOT status.normal THEN
            RETURN;
          IFEND;
          object_library_list^ [library_index] := program_file.local_file_name;
        IFEND;
      FOREND;
    IFEND;

    IF pmc$condition_specified IN program_attributes^.contents THEN
      NEXT library_enable_inhib_conditions IN library_program_description;
      NEXT enable_inhibit_conditions IN program_description;
      enable_inhibit_conditions^ := library_enable_inhib_conditions^;
    IFEND;

    IF pmc$load_map_file_specified IN program_attributes^.contents THEN
      clp$convert_string_to_file (library_program_attributes^.load_map_file, program_file, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      program_attributes^.load_map_file := program_file.local_file_name;
    IFEND;

    IF pmc$load_map_options_specified IN program_attributes^.contents THEN
      program_attributes^.load_map_options := library_program_attributes^.load_map_options;
    IFEND;

    IF pmc$term_error_level_specified IN program_attributes^.contents THEN
      program_attributes^.termination_error_level := library_program_attributes^.termination_error_level;
    IFEND;

    IF pmc$preset_specified IN program_attributes^.contents THEN
      program_attributes^.preset := library_program_attributes^.preset;
    IFEND;

    IF pmc$max_stack_size_specified IN program_attributes^.contents THEN
      program_attributes^.maximum_stack_size := library_program_attributes^.maximum_stack_size;
    IFEND;

    IF pmc$debug_input_specified IN program_attributes^.contents THEN
      clp$convert_string_to_file (library_program_attributes^.debug_input, program_file, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      program_attributes^.debug_input := program_file.local_file_name;
    IFEND;

    IF pmc$debug_output_specified IN program_attributes^.contents THEN
      clp$convert_string_to_file (library_program_attributes^.debug_output, program_file, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      program_attributes^.debug_output := program_file.local_file_name;
    IFEND;

    IF pmc$abort_file_specified IN program_attributes^.contents THEN
      clp$convert_string_to_file (library_program_attributes^.abort_file, program_file, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      program_attributes^.abort_file := program_file.local_file_name;
    IFEND;

    IF pmc$debug_mode_specified IN program_attributes^.contents THEN
      program_attributes^.debug_mode := library_program_attributes^.debug_mode;
    IFEND;

  PROCEND convert_program_description;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] osp$activate_system_task', EJECT ??
*copyc osh$activate_system_task

  PROCEDURE [XDCL, #GATE] osp$activate_system_task
    (    name: ost$name;
     VAR status: ost$status);

    VAR
      execution_ring: ost$valid_ring,
      local_name: ost$name,
      local_status: ost$status,
      parameters: ^clt$parameter_list,
      program_description: ^llt$program_description,
      spy_identifier: pmt$spy_identifier,
      system_job_monitor: boolean;

    status.normal := TRUE;
    IF NOT avp$system_operator () THEN
      osp$set_status_abnormal ('  ', ofe$sou_not_active, 'SYSTEM_OPERATION', status);
      RETURN;
    IFEND;

    local_name := name;
    system_job_monitor := jmp$system_job () AND osp$executing_in_job_monitor ();
    osp$activate_system_task_r1 (local_name, system_job_monitor, program_description, parameters,
          spy_identifier, execution_ring, local_status);
    IF local_status.normal THEN

{ If the system job monitor task is activating the task, then execute the task immediately.
{ Otherwise, ready the system job monitor task so that it may execute the activated task.

      IF system_job_monitor THEN
        osp$execute_system_task (name, program_description, parameters, spy_identifier, execution_ring,
              local_status);
      ELSE
        tmp$ready_system_task (tmc$stid_job_monitor, local_status);
      IFEND;
    IFEND;
    osp$copy_local_status_to_status (local_status, status);

  PROCEND osp$activate_system_task;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE, UNSAFE] osp$active_system_task', EJECT ??

{ PURPOSE:
{   The purpose of this function is to return a boolean value indicating whether the executing task
{   is an active system task.

  FUNCTION [XDCL, #GATE, UNSAFE] osp$active_system_task: boolean;

    VAR
      entry: ^ost$system_task_execution_entry,
      ignored_status: ost$status,
      task_id: pmt$task_id;

    osp$active_system_task := FALSE;

{ If the executing task is not in the system job, it cannot be a system task.

    IF NOT jmp$system_job () THEN
      RETURN;
    IFEND;

{ Get the system task name of the executing task.

    pmp$get_task_id (task_id, ignored_status);
    osp$set_job_signature_lock (system_task_execution_lock);
    entry := system_task_execution_table;
    WHILE (entry <> NIL) AND (entry^.task_id <> task_id) DO
      entry := entry^.next_entry;
    WHILEND;
    osp$clear_job_signature_lock (system_task_execution_lock);
    IF entry = NIL THEN
      RETURN;
    IFEND;

{ Check the system task table to see if the system task has been deactivated.

    osp$active_system_task := osp$active_system_task_r1 (entry^.task_name);

  FUNCEND osp$active_system_task;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] osp$check_sys_task_completions', EJECT ??

{ PURPOSE:
{   The purpose of this request is to check to task_status variables of all executing system tasks to
{   determine if any task has terminated.  If a task has terminated, its termination status is recorded
{   in the system task table.
{ NOTES:
{   This request should only be called in the system job.  It is a no-op if called in another job.

  PROCEDURE [XDCL] osp$check_sys_task_completions;

    VAR
      entry: ^ost$system_task_execution_entry,
      ptr_to_entry: ^^ost$system_task_execution_entry;

    osp$set_job_signature_lock (system_task_execution_lock);
    entry := system_task_execution_table;
    ptr_to_entry := ^system_task_execution_table;
    WHILE entry <> NIL DO
      IF entry^.task_status.complete THEN
        osp$store_system_task_status (entry^.task_name, entry^.task_status.status);
        ptr_to_entry^ := entry^.next_entry;
        FREE entry IN osv$task_shared_heap^;
        entry := ptr_to_entry^;
      ELSE
        ptr_to_entry := ^entry^.next_entry;
        entry := entry^.next_entry;
      IFEND;
    WHILEND;
    osp$clear_job_signature_lock (system_task_execution_lock);

  PROCEND osp$check_sys_task_completions;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] osp$deactivate_system_task', EJECT ??
*copyc osh$deactivate_system_task

  PROCEDURE [XDCL, #GATE] osp$deactivate_system_task
    (    name: ost$name;
     VAR status: ost$status);

    VAR
      local_name: ost$name,
      local_status: ost$status,
      system_job_monitor: boolean;

    status.normal := TRUE;
    IF NOT avp$system_operator () THEN
      osp$set_status_abnormal ('  ', ofe$sou_not_active, 'SYSTEM_OPERATION', status);
      RETURN;
    IFEND;

    local_name := name;
    system_job_monitor := jmp$system_job () AND osp$executing_in_job_monitor ();
    osp$deactivate_system_task_r1 (local_name, system_job_monitor, local_status);
    IF local_status.normal THEN

{ If the system job monitor task is deactivating the task, then terminate the task immediately.
{ Otherwise, ready the system job monitor task so that it may terminate the deactivated task.

      IF system_job_monitor THEN
        osp$terminate_system_task (name);
      ELSE
        tmp$ready_system_task (tmc$stid_job_monitor, local_status);
      IFEND;
    IFEND;
    osp$copy_local_status_to_status (local_status, status);

  PROCEND osp$deactivate_system_task;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] osp$define_system_task', EJECT ??
*copyc osh$define_system_task

  PROCEDURE [XDCL, #GATE] osp$define_system_task
    (    name: ost$name;
         automatic_restart: boolean;
         deactivate_task_option: ost$termination_type;
         idle_task_option: ost$termination_type;
         restart_after_idle: boolean;
         spy_identifier: pmt$spy_identifier;
         execution_ring: ost$valid_ring;
         program_description: ^llt$program_description;
         parameters: ^clt$parameter_list;
     VAR status: ost$status);

    VAR
      local_automatic_restart: boolean,
      local_deactivate_task_option: ost$termination_type,
      local_execution_ring: ost$valid_ring,
      local_idle_task_option: ost$termination_type,
      local_name: ost$name,
      local_parameters: ^clt$parameter_list,
      local_program_description: ^llt$program_description,
      local_restart_after_idle: boolean,
      local_spy_identifier: pmt$spy_identifier,
      local_status: ost$status;

    status.normal := TRUE;
    IF NOT avp$system_operator () THEN
      osp$set_status_abnormal ('  ', ofe$sou_not_active, 'SYSTEM_OPERATION', status);
      RETURN;
    ELSEIF execution_ring < avp$ring_min () THEN
      osp$set_status_abnormal ('  ', ose$exec_ring_below_min_ring, '', status);
      RETURN;
    IFEND;

    local_name := name;
    local_automatic_restart := automatic_restart;
    local_deactivate_task_option := deactivate_task_option;
    local_idle_task_option := idle_task_option;
    local_restart_after_idle := restart_after_idle;
    local_spy_identifier := spy_identifier;
    local_execution_ring := execution_ring;
    IF program_description = NIL THEN
      local_program_description := NIL;
    ELSE
      PUSH local_program_description: [[REP #SIZE (program_description^) OF cell]];
      local_program_description^ := program_description^;
    IFEND;
    IF parameters = NIL THEN
      local_parameters := NIL;
    ELSE
      PUSH local_parameters: [[REP #SIZE (parameters^) OF cell]];
      local_parameters^ := parameters^;
    IFEND;
    osp$define_system_task_r1 (local_name, local_automatic_restart, local_deactivate_task_option,
          local_idle_task_option, local_restart_after_idle, local_spy_identifier, local_execution_ring,
          local_program_description, local_parameters, local_status);
    osp$copy_local_status_to_status (local_status, status);

  PROCEND osp$define_system_task;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] osp$delete_system_task', EJECT ??
*copyc osh$delete_system_task

  PROCEDURE [XDCL, #GATE] osp$delete_system_task
    (    name: ost$name;
     VAR status: ost$status);

    CONST
      one_half_second = 500;

    VAR
      endtime: integer,
      local_name: ost$name,
      local_status: ost$status,
      task_executing: boolean;

    status.normal := TRUE;
    IF NOT avp$system_operator () THEN
      osp$set_status_abnormal ('  ', ofe$sou_not_active, 'SYSTEM_OPERATION', status);
      RETURN;
    IFEND;

{ Wait up to 20 seconds for task to complete if it is still executing.

    local_name := name;
    endtime := #FREE_RUNNING_CLOCK (0) + 20000000;
    REPEAT
      osp$delete_system_task_r1 (local_name, task_executing, local_status);
      IF NOT local_status.normal THEN
        osp$copy_local_status_to_status (local_status, status);
        RETURN;
      ELSEIF NOT task_executing THEN
        RETURN;
      IFEND;
    UNTIL endtime < #FREE_RUNNING_CLOCK (0);

    osp$set_status_abnormal ('  ', ose$system_task_still_running, name, status);

  PROCEND osp$delete_system_task;
?? OLDTITLE ??
?? NEWTITLE := 'osp$execute_system_task', EJECT ??

{ PURPOSE:
{   The purpose of this request is to execute a system task.
{ NOTES:
{   This request must be called only in the system job monitor task.

  PROCEDURE osp$execute_system_task
    (    name: ost$name;
         program_description: ^llt$program_description;
         parameters: ^clt$parameter_list;
         spy_identifier: pmt$spy_identifier;
         execution_ring: ost$valid_ring;
     VAR status: ost$status);

    VAR
      condition_count: 0 .. 1,
      converted_program_description: ^pmt$program_description,
      entry: ^ost$system_task_execution_entry,
      file_count: 0 .. pmc$max_object_file_list,
      ignored_status: ost$status,
      library_count: 0 .. pmc$max_library_list,
      module_count: 0 .. pmc$max_module_list,
      original_program_attributes: ^llt$program_attributes,
      original_program_description: ^llt$program_description;

    status.normal := TRUE;

{ Allocate and initialize a new system task execution table entry.

    ALLOCATE entry IN osv$task_shared_heap^;
    entry^.task_name := name;

{ Convert program description to the form required by pmp$execute_task.

    original_program_description := program_description;
    RESET original_program_description;
    NEXT original_program_attributes IN original_program_description;
    IF pmc$object_file_list_specified IN original_program_attributes^.contents THEN
      file_count := original_program_attributes^.number_of_object_files;
    ELSE
      file_count := 0;
    IFEND;
    IF pmc$module_list_specified IN original_program_attributes^.contents THEN
      module_count := original_program_attributes^.number_of_modules;
    ELSE
      module_count := 0;
    IFEND;
    IF pmc$library_list_specified IN original_program_attributes^.contents THEN
      library_count := original_program_attributes^.number_of_libraries;
    ELSE
      library_count := 0;
    IFEND;
    IF pmc$condition_specified IN original_program_attributes^.contents THEN
      condition_count := 1;
    ELSE
      condition_count := 0;
    IFEND;
    PUSH converted_program_description: [[REP #SIZE (pmt$program_attributes) +
          (file_count * #SIZE (amt$local_file_name)) + (module_count *
          #SIZE (pmt$program_name)) + (library_count * #SIZE (amt$local_file_name)) +
          (condition_count * #SIZE (pmt$enable_inhibit_conditions)) OF cell]];
    convert_program_description (original_program_description, converted_program_description, status);

    IF status.normal THEN
      IF spy_identifier <> 0 THEN
        pmp$set_spy_identifier (spy_identifier, 0, status);
      IFEND;
    IFEND;

    IF status.normal THEN
      pmp$execute_with_less_privilege (execution_ring, converted_program_description^, parameters^,
            osc$nowait, FALSE, entry^.task_id, entry^.task_status, status);
      IF spy_identifier <> 0 THEN
        pmp$set_spy_identifier (0, 0, ignored_status);
      IFEND;
    IFEND;

    IF NOT status.normal THEN

{ Store the abnormal status as the task termination status.  Storing it in the system task execution table
{ (rather than the system task table) allows other tasks to be processed on this pass thru the main loop of
{ osp$manage_system_tasks.  The abnormal status must also be returned to the caller.

      entry^.task_status.status := status;
      entry^.task_status.complete := TRUE;
    IFEND;

{ Link the new entry into the system task execution table.

    osp$set_job_signature_lock (system_task_execution_lock);
    entry^.next_entry := system_task_execution_table;
    system_task_execution_table := entry;
    osp$clear_job_signature_lock (system_task_execution_lock);

  PROCEND osp$execute_system_task;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] osp$get_system_task_data', EJECT ??

{ PURPOSE:
{   The purpose of this request is to return display information for one or all system tasks.
{ NOTES:
{   If display information is requested for all tasks, this request always returns a count of the number of
{   executing system tasks.  This allows the caller to allocate a data structure sufficiently large to hold
{   display information for all tasks.

  PROCEDURE [XDCL, #GATE] osp$get_system_task_data
    (    criteria: ost$system_task_data_criteria;
     VAR system_task_data: ost$system_task_display_data;
     VAR system_task_count: integer;
     VAR status: ost$status);

    VAR
      local_criteria: ost$system_task_data_criteria,
      local_status: ost$status,
      local_system_task_count: integer,
      local_system_task_data: ^ost$system_task_display_data;

    status.normal := TRUE;
    IF NOT (avp$system_operator () OR avp$system_displays ()) THEN
      osp$set_status_abnormal ('  ', ofe$sou_not_active, 'SYSTEM_OPERATION or SYSTEM_DISPLAYS', status);
      RETURN;
    IFEND;
    IF UPPERBOUND (system_task_data) < 1 THEN
      RETURN;
    ELSE
      PUSH local_system_task_data: [1 .. UPPERBOUND (system_task_data)];
    IFEND;
    local_criteria := criteria;
    osp$get_system_task_data_r1 (local_criteria, local_system_task_data^, local_system_task_count,
          local_status);
    system_task_data := local_system_task_data^;
    system_task_count := local_system_task_count;
    osp$copy_local_status_to_status (local_status, status);

  PROCEND osp$get_system_task_data;
?? OLDTITLE ??
?? NEWTITLE := 'osp$log_terminated_task', EJECT ??

{ PURPOSE:
{   The purpose of this request is to generate a system log entry reporting the unexpected
{   termination of a system task.

  PROCEDURE osp$log_terminated_task
    (    task_name: ost$name;
         termination_status: ost$status;
     VAR status: ost$status);

    CONST
      separator_1 = ' $!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$',
      separator_2 = ' $!$!$-------------------------------------------------------$!$!$';

    VAR
      length: integer,
      line: string (80),
      log_name_selections: array [1 .. 1] of ost$name,
      status_condition: string (11);

    line := ' ';
    log_name_selections [1] := 'SYSTEM';
    IF NOT termination_status.normal THEN
      clp$log_comment (separator_1, log_name_selections, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      line := ' $!$!$                                 terminated with';
      line (8, 31) := task_name;
      clp$log_comment (line, log_name_selections, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      line := ' $!$!$    ERROR:  CONDITION= xx ';
      line (30) := $CHAR ((termination_status.condition DIV 1000000(16)) DIV 100(16));
      line (31) := $CHAR ((termination_status.condition DIV 1000000(16)) MOD 100(16));
      STRINGREP (status_condition, length, (termination_status.condition MOD 1000000(16)));
      line (33, length) := status_condition;
      line (33 + length, * ) := ', TEXT=';
      clp$log_comment (line, log_name_selections, status);
      clp$log_comment (termination_status.text.value (1, termination_status.text.size), log_name_selections,
            status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      clp$log_comment (separator_2, log_name_selections, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    ELSE { normal termination }
      clp$log_comment (separator_1, log_name_selections, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      line := ' $!$!$                                 terminated with NORMAL status.';
      line (8, 31) := task_name;
      clp$log_comment (line, log_name_selections, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      clp$log_comment (separator_2, log_name_selections, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    IFEND;

  PROCEND osp$log_terminated_task;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] osp$manage_system_tasks', EJECT ??

{ PURPOSE:
{   The purpose of this request is to perform any actions that are needed to support system task execution.
{   Both the system task table and the system task execution table are scanned for events that require
{   action.
{ DESIGN:
{   First, the termination status of any system that has completed is moved from the system task execution
{   table to the system task table.  Then, a ring 1 helper is called to examine the system task table to
{   determine if any action is required.  If an action is required, the helper returns a description of the
{   action required and updates the system task table to indicate that the action has been taken.  This
{   procedure then performs the required action.  The helper is called repeatedly until no actions are
{   required.
{ NOTES:
{   This request must be called only in the system job monitor task.

  PROCEDURE [XDCL, #GATE] osp$manage_system_tasks
    (VAR short_wait: boolean;
     VAR status: ost$status);

    CONST
      line_template = ' ---- Task                                                 ----';

    VAR
      line: string (65),
      work_to_do: ost$system_task_work_to_do;

    status.normal := TRUE;
    short_wait := FALSE;
    IF NOT (jmp$system_job () AND osp$executing_in_job_monitor ()) THEN
      osp$set_status_abnormal ('  ', ose$not_system_job_monitor, 'osp$manage_system_tasks', status);
      RETURN;
    IFEND;

    osp$check_sys_task_completions;

    WHILE TRUE DO
      osp$scan_system_task_table (work_to_do);
      IF work_to_do.log_task_status THEN
        osp$log_terminated_task (work_to_do.task_name, work_to_do.task_status, {ignore} status);
        status.normal := TRUE;
      IFEND;
      CASE work_to_do.kind OF
      = osc$st_no_work_to_do =
        RETURN;
      = osc$st_execute_task =
        osp$execute_system_task (work_to_do.task_name, work_to_do.program_description,
              work_to_do.parameters, work_to_do.spy_identifier, work_to_do.execution_ring, status);
        IF NOT status.normal THEN
          short_wait := TRUE;
          status.normal := TRUE;
        IFEND;
        IF work_to_do.first_execution THEN
          line := line_template;
          line (12, 8) := 'started:';
          line (26, 31) := work_to_do.task_name;
          pmp$log (line, {ignore} status);
          status.normal := TRUE;
        ELSE
          line := line_template;
          line (12, 10) := 'restarted:';
          line (26, 31) := work_to_do.task_name;
          clp$put_job_command_response (line, {ignore} status);
          status.normal := TRUE;
        IFEND;

      = osc$st_terminate_task =
        osp$terminate_system_task (work_to_do.task_name);

      = osc$st_deactivate_task =
        line := line_template;
        line (12, 12) := 'deactivated:';
        line (26, 31) := work_to_do.task_name;
        clp$put_job_command_response (line, {ignore} status);
        status.normal := TRUE;
      CASEND;
    WHILEND;

  PROCEND osp$manage_system_tasks;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] osp$terminate_system_task', EJECT ??

{ PURPOSE:
{   The purpose of this request is to terminate an executing system task.
{ NOTES:
{   This request must be called only in the system job monitor task.

  PROCEDURE [XDCL] osp$terminate_system_task
    (    name: ost$name);

    VAR
      entry: ^ost$system_task_execution_entry,
      ignore_status: ost$status,
      task_id: pmt$task_id;

    osp$set_job_signature_lock (system_task_execution_lock);
    entry := system_task_execution_table;
    WHILE (entry <> NIL) AND (entry^.task_name <> name) DO
      entry := entry^.next_entry;
    WHILEND;
    osp$clear_job_signature_lock (system_task_execution_lock);
    IF entry = NIL THEN
      osp$system_error ('System task tables out of synch', NIL);
    ELSE
      task_id := entry^.task_id;
      pmp$terminate_task_without_wait (task_id, ignore_status);
    IFEND;

  PROCEND osp$terminate_system_task;
?? OLDTITLE ??
MODEND osm$system_task_maint_23d;
