?? NEWTITLE := 'NOS/VE Program Management : Inhibit Task Termination' ??
MODULE pmm$inhibit_task_termination;

{ PURPOSE:
{   This module contains routines callable only from ring 4.  These routines
{   are used to prevent the task from unexpectedly terminating when in a
{   critical section.  The routines are specifically made for use by AAM which
{   has its critical section in ring 4.
{
{ DESIGN:
{   pmp$push_inhibit_termination causes a counter to be incremented.  When this
{   counter is greater then zero, task termination will be "stacked" until the
{   counter returns to zero.  pmp$pop_inhibit_termination causes the counter to
{   be decremented.  If it causes the counter to return to zero, the task will
{   be terminated at this point if a terminate request had been stacked.
{   pmp$terminated_while_inhibited is a function which returns true if a
{   terminate request has been stacked.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc oss$job_paged_literal
*copyc oss$task_private
*copyc ost$caller_identifier
*copyc ost$stack_frame_save_area
*copyc pme$condition_exceptions
*copyc pme$execution_exceptions
*copyc pme$insufficient_privilege
*copyc pme$pop_inhibit_caused_term
*copyc pme$push_inhibit_too_deep
*copyc pmt$minimum_save_area
*copyc pmt$task_term_inhibit_count
?? POP ??
*copyc osp$disestablish_cond_handler
*copyc osp$establish_condition_handler
*copyc osp$executing_in_job_monitor
*copyc osp$generate_log_message
*copyc osp$set_status_condition
*copyc osp$set_status_from_condition
*copyc pmp$abort
*copyc pmp$apd_call_to_users_procedure
*copyc pmp$continue_to_cause
*copyc pmp$validate_previous_save_area
*copyc pmv$debug_logging_enabled
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??

  VAR
    pmv$task_term_inhibit_count: [XDCL, oss$task_private]
          pmt$task_term_inhibit_count := 0,
    pmv$task_termination_attempted: [XDCL, oss$task_private] boolean := FALSE;

  TYPE
    p_address = packed record
      filler: 0 .. 0fffff(16),
      seg_offset: 0 .. 0fffffffffff(16),
    recend,

    pointer_to_procedure = record
      case dummy: 0 .. 1 of
      = 0 =
        procedure_pointer: ^procedure,
      = 1 =
        cbp: ^p_address,
      casend,
    recend;

  VAR
    apd_call_to_users_procedure: [STATIC, READ, oss$job_paged_literal]
          pointer_to_procedure := [0, ^pmp$apd_call_to_users_procedure];

?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE]  pmp$pop_inhibit_termination', EJECT ??
*copy pmh$pop_inhibit_termination

  PROCEDURE [XDCL, #GATE] pmp$pop_inhibit_termination;


    VAR
      current_a2: ^cell,
      frame: ^ost$stack_frame_save_area,
      local_status: ost$status,
      log_status: ^ost$status,
      stack_frame_word_p: ^pmt$os_stack_frame_word,
      psa: ^ost$stack_frame_save_area; {previous_save_area}

    IF pmv$task_term_inhibit_count > 0 THEN
      pmv$task_term_inhibit_count := pmv$task_term_inhibit_count - 1;
      IF pmv$task_term_inhibit_count = 0 THEN
        frame := #PREVIOUS_SAVE_AREA ();

        stack_frame_word_p := frame^.minimum_save_area.a1_current_stack_frame;

      /find_establishing_frame/
        WHILE NOT ((#RING (frame) = osc$sj_ring_1) AND
              frame^.minimum_save_area.frame_descriptor.on_condition_flag AND
              frame^.minimum_save_area.frame_descriptor.critical_frame_flag AND
              stack_frame_word_p^.terminate_inhibit_frame) DO
          psa := frame^.minimum_save_area.a2_previous_save_area;
          current_a2 := frame^.minimum_save_area.a2_previous_save_area;
          IF (psa = NIL) OR (#RING (psa) > osc$sj_ring_1) THEN
            frame := NIL;
            EXIT /find_establishing_frame/;
          ELSEIF (((psa^.minimum_save_area.a2_previous_save_area = NIL) OR
                ((#OFFSET (psa^.minimum_save_area.a2_previous_save_area) >=
                0) AND ((#OFFSET (psa^.minimum_save_area.
                a2_previous_save_area) MOD 8) = 0))) AND
                (current_a2 = psa^.minimum_save_area.
                a0_dynamic_space_pointer) AND (psa^.minimum_save_area.
                frame_descriptor.a_terminating > 1)) THEN
            frame := psa;
          ELSE
            osp$set_status_condition (pme$inconsistent_stack, local_status);
            pmp$abort (local_status);
          IFEND;
          stack_frame_word_p := frame^.minimum_save_area.
                a1_current_stack_frame;
        WHILEND /find_establishing_frame/;

        IF frame <> NIL THEN
          stack_frame_word_p^.terminate_inhibit_frame := FALSE;
          frame^.minimum_save_area.frame_descriptor.critical_frame_flag :=
                stack_frame_word_p^.block_exit_frame OR
                stack_frame_word_p^.debug_cff_frame OR
                (stack_frame_word_p^.ada_critical_frame AND
                (stack_frame_word_p^.ada_critical_frame_count <> 0));
        IFEND;

        IF pmv$task_termination_attempted THEN
          IF pmv$debug_logging_enabled THEN
            osp$set_status_condition (pme$pop_inhibit_caused_term,
                  local_status);
            PUSH log_status;
            osp$generate_log_message ($pmt$ascii_logset
                  [pmc$system_log, pmc$job_log], local_status, log_status^);
          IFEND;
          pmv$task_termination_attempted := FALSE;
          osp$set_status_condition (pme$terminated_by_parent, local_status);
          pmp$abort (local_status);
        IFEND;
      IFEND;
    IFEND;

  PROCEND pmp$pop_inhibit_termination;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE]  pmp$push_inhibit_termination', EJECT ??
*copy pmh$push_inhibit_termination

  PROCEDURE [XDCL, #GATE] pmp$push_inhibit_termination;

    VAR
      caller_id: ost$caller_identifier,
      current_a2: ^cell,
      frame: ^ost$stack_frame_save_area,
      local_status: ost$status,
      stack_frame_word_p: ^pmt$os_stack_frame_word,
      p: ^p_address,
      psa: ^ost$stack_frame_save_area; {previous_save_area}

    IF osp$executing_in_job_monitor () THEN
      RETURN;
    IFEND;
    #CALLER_ID (caller_id);
    IF caller_id.ring <> osc$sj_ring_1 THEN
      osp$set_status_condition (pme$insufficient_privilege, local_status);
      pmp$abort (local_status);
    IFEND;
    IF pmv$task_term_inhibit_count = pmc$max_task_term_inhibits THEN
      osp$set_status_condition (pme$push_inhibit_too_deep, local_status);
      pmp$abort (local_status);
    ELSEIF pmv$task_term_inhibit_count = 0 THEN

      frame := #PREVIOUS_SAVE_AREA ();

      p := #LOC (frame);
      WHILE (#RING (frame) < osc$sj_ring_1) OR
            (p^.seg_offset = apd_call_to_users_procedure.cbp^.seg_offset) DO
        psa := frame^.minimum_save_area.a2_previous_save_area;
        current_a2 := frame^.minimum_save_area.a2_previous_save_area;
        IF NOT (((psa^.minimum_save_area.a2_previous_save_area = NIL) OR
              ((#OFFSET (psa^.minimum_save_area.a2_previous_save_area) >=
              0) AND ((#OFFSET (psa^.minimum_save_area.
              a2_previous_save_area) MOD 8) = 0))) AND
              (current_a2 = psa^.minimum_save_area.
              a0_dynamic_space_pointer) AND (psa^.minimum_save_area.
              frame_descriptor.a_terminating > 1)) THEN
          osp$set_status_condition (pme$inconsistent_stack, local_status);
          pmp$abort (local_status);
        IFEND;
        frame := psa;
        p := #LOC (frame);
      WHILEND;

      stack_frame_word_p := frame^.minimum_save_area.a1_current_stack_frame;
      IF NOT frame^.minimum_save_area.frame_descriptor.on_condition_flag THEN
        stack_frame_word_p^.block_exit_frame := FALSE;
        stack_frame_word_p^.debug_cff_frame := FALSE;
        stack_frame_word_p^.ada_critical_frame := FALSE;
        stack_frame_word_p^.ada_critical_frame_count := 0;
        stack_frame_word_p^.established_handler := NIL;
      IFEND;

      frame^.minimum_save_area.frame_descriptor.critical_frame_flag := TRUE;
      stack_frame_word_p^.terminate_inhibit_frame := TRUE;
      frame^.minimum_save_area.frame_descriptor.on_condition_flag := TRUE;
    IFEND;
    pmv$task_term_inhibit_count := pmv$task_term_inhibit_count + 1;

  PROCEND pmp$push_inhibit_termination;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE]  pmp$terminated_while_inhibited', EJECT ??
*copy pmh$terminated_while_inhibited

  FUNCTION [XDCL, #GATE] pmp$terminated_while_inhibited: boolean;

    VAR
      caller_id: ost$caller_identifier,
      local_status: ost$status;

    #CALLER_ID (caller_id);
    IF caller_id.ring <> osc$sj_ring_1 THEN
      osp$set_status_condition (pme$insufficient_privilege, local_status);
      pmp$abort (local_status);
    IFEND;

    pmp$terminated_while_inhibited := pmv$task_termination_attempted;

  FUNCEND pmp$terminated_while_inhibited;
?? OLDTITLE ??
MODEND pmm$inhibit_task_termination;

