?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE: Program Management - Program Conditions' ??
MODULE pmm$dispose_of_traps;




{   PURPOSE:
{     The purpose of this module is to confine the knowledge of disposing
{     of traps - it is the first CYBIL module to execute in the trap
{     processor.

{   DESIGN:
{     The procedures contained in this module have an execution bracket
{     of 2, 13.

{     One of the purposes of the trap handler is to protect task termination's
{     stack frame popper.  When any trap occurs, a test is made to see if the
{     trap handler needs protect popper.  If it does, it protects popper by
{     a local variable "protect_popper".  If this is true, and the trap handler's
{     block_exit handler gets control, the interface pmp$pop_all_stack_frames is
{     called.

?? NEWTITLE := 'Global Declarations Referenced by this Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc osc$processor_defined_registers
*copyc osd$registers
*copyc osd$virtual_address
*copyc oss$job_paged_literal
*copyc ost$name
*copyc ost$stack_frame_save_area
*copyc ost$status
*copyc pme$push_inhibit_but_no_pop
*copyc pmt$condition
*copyc pmt$debug_environment
*copyc pmt$os_stack_frame_word
?? POP ??
*copyc i#disable_traps
*copyc i#enable_traps
*copyc osp$disestablish_cond_handler
*copyc osp$establish_block_exit_hndlr
*copyc osp$set_status_condition
*copyc pmp$abort
*copyc pmp$activate_ring_alarm
*copyc pmp$await_ada_task
*copyc pmp$continue_to_cause
*copyc pmp$dispose_of_delayed_cond
*copyc pmp$dispose_ucr_conditions
*copyc pmp$exit
*copyc pmp$get_debug_environment
*copyc pmp$pop_all_stack_frames
*copyc pmp$post_debug_environment
*copyc pmp$set_popper_handler_activity
*copyc tmp$dispose_of_monitor_faults
*copyc tmp$dispose_preemptive_commo
*copyc tmp$post_monitor_fault_sfsa
*copyc pmv$popper_handler_established
*copyc pmv$task_execution_phase
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] pmp$dispose_of_traps', EJECT ??
*copy pmh$dispose_of_traps

  PROCEDURE [XDCL] pmp$dispose_of_traps
    (    sfsa: ^ost$stack_frame_save_area);

    VAR
      critical_frame: boolean,
      debug_environment: pmt$debug_environment,
      debug_index: 0 .. 31,
      debug_trap: boolean,
      local_status: ost$status,
      monitor_fault_present: boolean,
      need_to_protect_popper: boolean,
      on_condition: boolean,
      os_stack_frame_word: ^pmt$os_stack_frame_word,
      p_ring: ost$ring,
      psa_ring: ost$ring,
      ring_status: ost$status,
      system_core_debugger_inactive: boolean,
      trap_enables: 0 .. 3,
      ucr: ost$user_conditions,
      x_frame: ^ost$stack_frame_save_area;

?? NEWTITLE := 'dispose_of_nonlocal_exit - dispose of traps', EJECT ??

{ PURPOSE:
{   This procedure (condition handler) ensures that:
{   1.  the system uses of free flag (ring alarm and preemptive communication)
{       are not circumvented by a non local exit;
{   2.  no outstanding condition is circumvented by a non local exit;
{   3.  the debug environment is popped if the trap was debug -
{       pmp$get_debug_environment.
{
{ NOTES:
{   If we happen to trap before the block exit handler gets established it is
{   possible that this block exit handler will not get the opportunity to
{   really execute.

    PROCEDURE dispose_of_nonlocal_exit
      (    condition: pmt$condition;
           condition_descriptor: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR status: ost$status);

      VAR
        trap_enables: 0 .. 3;

      i#disable_traps (trap_enables);
      osp$establish_block_exit_hndlr (^dispose_of_nonlocal_exit);
      i#enable_traps (trap_enables);

      IF (osc$free_flag IN ucr) THEN
        IF monitor_fault_present THEN
          tmp$dispose_of_monitor_faults (sfsa);
        IFEND;

        tmp$dispose_preemptive_commo (tmc$free_flag);

        IF (sfsa^.minimum_save_area.p_register.pva.ring > osc$tmtr_ring) THEN
          pmp$dispose_of_delayed_cond (sfsa);
        IFEND;

        ucr := (ucr - $ost$user_conditions [osc$free_flag]);
      IFEND;

      IF critical_frame THEN
        IF NOT (on_condition AND (os_stack_frame_word^.block_exit_frame OR
              os_stack_frame_word^.debug_cff_frame)) THEN
          ucr := (ucr - $ost$user_conditions [osc$critical_frame_flag]);
        IFEND;
      IFEND;

      IF (osc$keypoint IN ucr) THEN
        ucr := (ucr - $ost$user_conditions [osc$keypoint]);
      IFEND;

      IF (ucr <> $ost$user_conditions []) THEN
        pmp$dispose_ucr_conditions (ucr, sfsa, debug_index);
      IFEND;

{ After all other ucr conditions have been processed, process the task
{ termination inhibit and ADA critical frame flags.

      IF on_condition AND critical_frame THEN
        #SPOIL (os_stack_frame_word^);
        IF os_stack_frame_word^.terminate_inhibit_frame THEN
          os_stack_frame_word^.terminate_inhibit_frame := FALSE;
          #SPOIL (os_stack_frame_word^);
          osp$set_status_condition (pme$push_inhibit_but_no_pop, local_status);
          pmp$abort (local_status);
        IFEND;

{ Do not allow the task to continue if this stack frame is an ADA critical
{ frame with a non-zero frame count.  The task must wait until all tasks with
{ this critical frame have terminated.

        IF (os_stack_frame_word^.ada_critical_frame AND (os_stack_frame_word^.ada_critical_frame_count <> 0))
              THEN
          pmp$await_ada_task (os_stack_frame_word);
        IFEND;
      IFEND;

      IF debug_trap AND system_core_debugger_inactive THEN
        pmp$get_debug_environment (debug_environment);

{it is not necessary to update the debug environment registers on a non-local exit

      IFEND;

      IF critical_frame THEN
        sfsa^.minimum_save_area.frame_descriptor.on_condition_flag := FALSE;
        sfsa^.minimum_save_area.frame_descriptor.critical_frame_flag := FALSE;
      IFEND;

      i#disable_traps (trap_enables);
      osp$disestablish_cond_handler;

      IF need_to_protect_popper THEN
        pmp$set_popper_handler_activity (FALSE);
        IF pmv$task_execution_phase = pmc$task_popping_stack_frames THEN
          i#enable_traps (trap_enables);
          pmp$pop_all_stack_frames;
        ELSE
          need_to_protect_popper := FALSE;
        IFEND;
      IFEND;
      i#enable_traps (trap_enables);
    PROCEND dispose_of_nonlocal_exit;
?? OLDTITLE ??
?? EJECT ??

    TYPE
      debug_mask_type = packed record
        filler: array [1 .. 7] of cell,
        unused: boolean,
        mask: ost$debug_mask,
      recend,
      user_mask_type = set of 0 .. 63;

    CONST
      debug_mask_bit = 56;

    VAR
      converter: record
        case 0 .. 2 of
        = 0 =
          register: integer,
        = 1 =
          debug_mask: debug_mask_type,
        = 2 =
          user_mask: user_mask_type,
        casend,
      recend,

      debug_mask: debug_mask_type;

    p_ring := sfsa^.minimum_save_area.p_register.pva.ring;
    psa_ring := #RING (sfsa^.minimum_save_area.a2_previous_save_area);
    ucr := (sfsa^.user_condition_register * sfsa^.minimum_save_area.user_mask);
    debug_index := (#READ_REGISTER (osc$pr_debug_index) DIV 2);
    system_core_debugger_inactive := (#READ_REGISTER (osc$pr_debug_list_pointer) DIV 100000000000(16)) <> 1;
    debug_trap := (osc$debug IN ucr);
    critical_frame := (osc$critical_frame_flag IN ucr);
    on_condition := sfsa^.minimum_save_area.frame_descriptor.on_condition_flag;
    os_stack_frame_word := sfsa^.minimum_save_area.a1_current_stack_frame;

    IF system_core_debugger_inactive THEN
      IF debug_trap THEN
        debug_environment.debug_index := #READ_REGISTER (osc$pr_debug_index);
        converter.register := #READ_REGISTER (osc$pr_debug_mask_reg);
        debug_mask := converter.debug_mask;
        debug_environment.debug_mask := debug_mask.mask;
        pmp$post_debug_environment (debug_environment);
      IFEND;

{clear the debug bit in the user mask register

      converter.register := #READ_REGISTER (osc$pr_user_mask_reg);
      converter.user_mask := converter.user_mask - $user_mask_type [debug_mask_bit];
      #WRITE_REGISTER (osc$pr_user_mask_reg, converter.register);
    IFEND;
?? EJECT ??
    IF osc$free_flag IN ucr THEN
      tmp$post_monitor_fault_sfsa (sfsa, monitor_fault_present);
    ELSE
      monitor_fault_present := FALSE;
    IFEND;

    osp$establish_block_exit_hndlr (^dispose_of_nonlocal_exit);

    need_to_protect_popper := NOT pmv$popper_handler_established;
    IF need_to_protect_popper THEN
      pmp$set_popper_handler_activity (need_to_protect_popper);
    IFEND;
    i#enable_traps (trap_enables);

    IF (osc$free_flag IN ucr) THEN
      IF monitor_fault_present THEN
        tmp$dispose_of_monitor_faults (sfsa);
      IFEND;
      tmp$dispose_preemptive_commo (tmc$free_flag);
      sfsa^.user_condition_register := ucr;

      IF sfsa^.minimum_save_area.p_register.pva.ring > osc$tmtr_ring THEN
        pmp$dispose_of_delayed_cond (sfsa);
      IFEND;
      ucr := ucr - $ost$user_conditions [osc$free_flag];
    IFEND;

    IF critical_frame AND NOT (on_condition AND (os_stack_frame_word^.block_exit_frame OR
          os_stack_frame_word^.debug_cff_frame)) THEN
      ucr := (ucr - $ost$user_conditions [osc$critical_frame_flag]);
    IFEND;

    IF (osc$keypoint IN ucr) THEN
      ucr := (ucr - $ost$user_conditions [osc$keypoint]);
    IFEND;

    IF (ucr <> $ost$user_conditions []) THEN
      pmp$dispose_ucr_conditions (ucr, sfsa, debug_index);
    IFEND;

{ After all other ucr conditions have been processed, process the task
{ termination inhibit and ADA critical frame flags.

    IF on_condition AND critical_frame THEN
      #SPOIL (os_stack_frame_word^);
      IF os_stack_frame_word^.terminate_inhibit_frame THEN
        os_stack_frame_word^.terminate_inhibit_frame := FALSE;
        #SPOIL (os_stack_frame_word^);
        osp$set_status_condition (pme$push_inhibit_but_no_pop, local_status);
        pmp$abort (local_status);
      IFEND;

{ Do not allow the task to continue if this stack frame is an ADA critical
{ frame with a non-zero frame count.  The task must wait until all tasks with
{ this critical frame have terminated.

      IF (os_stack_frame_word^.ada_critical_frame AND (os_stack_frame_word^.ada_critical_frame_count <> 0))
            THEN
        pmp$await_ada_task (os_stack_frame_word);
      IFEND;
    IFEND;

    IF critical_frame THEN
      sfsa^.minimum_save_area.frame_descriptor.on_condition_flag := FALSE;
      sfsa^.minimum_save_area.frame_descriptor.critical_frame_flag := FALSE;
    IFEND;

    i#disable_traps (trap_enables);

    IF debug_trap AND system_core_debugger_inactive THEN
      pmp$get_debug_environment (debug_environment);
      #WRITE_REGISTER (osc$pr_debug_index, debug_environment.debug_index);
      debug_mask.mask := debug_environment.debug_mask;
      converter.debug_mask := debug_mask;
      #WRITE_REGISTER (osc$pr_debug_mask_reg, converter.register);
    IFEND;

    osp$disestablish_cond_handler;

    IF need_to_protect_popper THEN
      pmp$set_popper_handler_activity (FALSE);
    IFEND;

  PROCEND pmp$dispose_of_traps;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] pmp$ring_crossing_procedure', EJECT ??
*copyc pmh$ring_crossing_procedure

  PROCEDURE [XDCL] pmp$ring_crossing_procedure;

    VAR
      activate_alarm: boolean,
      of_execution: ^cell,
      trap_enables: 0 .. 3,
      p_ring: ost$ring,
      activate_status: ost$status;

?? NEWTITLE := 'dispose_of_nonlocal_exit - ring_crossing_procedure', EJECT ??

{ PURPOSE:
{   This procedure is the block exit processor for PMP$RING_CROSSING_PROCEDURE.

    PROCEDURE dispose_of_nonlocal_exit
      (    condition: pmt$condition;
           condition_descriptor: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR status: ost$status);

      VAR
        trap_enables: 0 .. 3;


      i#disable_traps (trap_enables);
      osp$establish_block_exit_hndlr (^dispose_of_nonlocal_exit);
      i#enable_traps (trap_enables);

      tmp$dispose_preemptive_commo (tmc$recognition_ring_delay);
      osp$disestablish_cond_handler;

    PROCEND dispose_of_nonlocal_exit;

?? OLDTITLE, EJECT ??

    osp$establish_block_exit_hndlr (^dispose_of_nonlocal_exit);
    of_execution := ^p_ring;
    p_ring := #RING (of_execution);
    i#enable_traps (trap_enables);

    activate_alarm := FALSE;
    activate_status.normal := TRUE;

{Check for delayed preemption and potential activation of ring alarm.

    IF p_ring <= osc$tsrv_ring THEN
      tmp$dispose_preemptive_commo (tmc$recognition_ring_delay);
    IFEND;

    i#disable_traps (trap_enables);
    pmp$activate_ring_alarm (activate_alarm, activate_status);
    osp$disestablish_cond_handler;

    IF NOT activate_status.normal THEN
      i#enable_traps (trap_enables);
      pmp$exit (activate_status);
    IFEND;

  PROCEND pmp$ring_crossing_procedure;
?? OLDTITLE ??

MODEND pmm$dispose_of_traps;

