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


{   PURPOSE:
{     The purpose of this module is to confine the knowledge of the
{     condition environment stack and the delayed condition (ring alarm)
{     stacks.  All accesses to these stacks are via procedures in this module.

{   DESIGN:
{     This module is designed to execute in rings 2 - 3.  The XDCL, #GATEed
{     procedures have a call bracket of 13.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc osd$conditions
*copyc osd$registers
*copyc osd$virtual_address
*copyc ose$heap_full_exceptions
*copyc oss$task_private
*copyc ost$caller_identifier
*copyc ost$name
*copyc ost$stack_frame_save_area
*copyc ost$status
*copyc ost$virtual_machine_identifier
*copyc pmc$program_management_id
*copyc pmt$condition
*copyc pmt$established_handler
?? POP ??
*copyc i#disable_traps
*copyc i#restore_traps
*copyc osp$set_status_abnormal
*copyc osp$verify_system_privilege
*copyc pmp$delete_current_environ_r2
*copyc pmp$delete_environment_r2
*copyc pmp$get_current_environ_r2
*copyc pmp$log
*copyc pmp$post_current_environ_r2
*copyc syp$enable_job_free_flag
*copyc tmp$find_ring_crossing_frame

*copyc osv$task_private_heap
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??
*copyc pmt$condition_environment
*copyc pmt$delayed_condition
?? OLDTITLE ??
?? NEWTITLE := 'Manage Condition Environment Stack', EJECT ??

{    the condition_environment_stack in the tcb exists to support the
{    PMP$CONTINUE_TO_CAUSE Program Interface.
{
{    NOTE:
{      The design relies upon the assumption that NOS/VE procedures
{      residing in rings 1 - 3 will not overwrite the contents of the
{      condition_environment_stack.  If in fact this
{      assumption is not true and the condition_environment_stack is
{      overwritten, the consequence is dependent on 1) the procedure
{      which is disrupted by the overwrite and 2) the ring of that procedure's
{      caller:
{      1. PMP$POST_CURRENT_ENVIRONMENT
{         R2. broken task --> osp$system_error
{         R3 - R15. broken task --> pmp$exit
{
{      2. PMP$DELETE_CURRENT_ENVIRONMENT
{         R2. pme$stack_overwritten --> osp$system_error
{         R3 - R15. pme$stack_overwritten --> pmp$abort
{
{      3. PMP$GET_CURRENT_ENVIRONMENT
{         R2 - R15. abnormal status (pme$no_condition_to_continue) from
{                   pmp$continue_to_cause
{
{      4. PMP$DELETE_ENVIRONMENT
{         R2. pme$stack_overwritten --> osp$system_error
{         R3 - R15. pme$stack_overwritten --> pmp$abort
{
{  - The caller's ring is always put into the condition_environment_stack.
{    This is to insure that the caller is not given more privelege than he
{    currently has.

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

  PROCEDURE [XDCL, #GATE] pmp$get_current_environment
    (VAR environment: pmt$condition_environment;
     VAR environment_present: boolean;
     VAR status: ost$status);

    VAR
      caller: ost$caller_identifier;

    #CALLER_ID (caller);
    status.normal := TRUE;

    osp$verify_system_privilege;
    pmp$get_current_environ_r2 (caller.ring, environment, environment_present, status);

  PROCEND pmp$get_current_environment;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] pmp$delete_current_environment', EJECT ??

{ PURPOSE:
{   Pop the current environment from the condition_environment_stack.

  PROCEDURE [XDCL, #GATE] pmp$delete_current_environment
    (VAR status: ost$status);

    VAR
      caller: ost$caller_identifier;

    #CALLER_ID (caller);
    status.normal := TRUE;

    osp$verify_system_privilege;
    pmp$delete_current_environ_r2 (caller.ring, status);

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

  PROCEDURE [XDCL, #GATE] pmp$delete_environment
    (    critical_frame: ^ost$stack_frame_save_area;
     VAR status: ost$status);

    VAR
      caller: ost$caller_identifier;

    #CALLER_ID (caller);
    status.normal := TRUE;

    osp$verify_system_privilege;
    pmp$delete_environment_r2 (caller.ring, critical_frame, status);

  PROCEND pmp$delete_environment;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] pmp$post_current_environment', EJECT ??

{ PURPOSE:
{   push the environment onto the condition_environment_stack contained in the
{   task_control_block

  PROCEDURE [XDCL, #GATE] pmp$post_current_environment
    (    environment {input, output} : ^pmt$condition_environment);

    VAR
      caller: ost$caller_identifier,
      environment_stack: ^pmt$condition_environment;

    #CALLER_ID (caller);

    osp$verify_system_privilege;
    environment_stack := environment;
    pmp$post_current_environment_r2 (caller.ring, environment_stack);

  PROCEND pmp$post_current_environment;
?? OLDTITLE ??
?? OLDTITLE ??
?? NEWTITLE := 'Manage Delayed Condition Stacks', EJECT ??

  VAR
    pmv$activate_ring_alarm: [STATIC, oss$task_private {stack} ] array [osc$os_ring_1 .. osc$user_ring_1] of ^
          {BOUND} pmt$delayed_condition := [REP osc$user_ring_1 of NIL],

    pmv$ring_alarm: [STATIC, oss$task_private {stack} ] array [osc$tmtr_ring .. osc$user_ring_4] of
          ^ {BOUND} pmt$delayed_condition := [REP (osc$user_ring_4 - osc$tmtr_ring + 1) of NIL];

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

  PROCEDURE [XDCL, #GATE] pmp$activate_ring_alarm
    (VAR activate_ring_alarm: boolean;
     VAR status: ost$status);

    VAR
      activate_stack: ^ {BOUND} pmt$delayed_condition,
      caller_id: ost$caller_identifier,
      alarm_ring: ost$ring,
      x_frame: ^ost$stack_frame_save_area,
      callers_frame: ^ost$stack_frame_save_area,
      starting_frame: ^ost$stack_frame_save_area;

    #CALLER_ID (caller_id);
    osp$verify_system_privilege;
    callers_frame := #PREVIOUS_SAVE_AREA ();
    starting_frame := callers_frame^.minimum_save_area.a2_previous_save_area;
    tmp$find_ring_crossing_frame (starting_frame, x_frame, status);
    IF status.normal THEN
      alarm_ring := #RING (x_frame^.minimum_save_area.a2_previous_save_area);
      IF (pmv$activate_ring_alarm [caller_id.ring] <> NIL) THEN
        IF (pmv$ring_alarm [alarm_ring] = NIL) THEN
          pmv$ring_alarm [alarm_ring] := pmv$activate_ring_alarm [caller_id.ring];
        ELSE
          activate_stack := pmv$activate_ring_alarm [caller_id.ring];
          WHILE (activate_stack^.next_delayed_condition <> NIL) DO
            activate_stack := activate_stack^.next_delayed_condition;
          WHILEND;
          activate_stack^.next_delayed_condition := pmv$ring_alarm [alarm_ring];
          pmv$ring_alarm [alarm_ring] := pmv$activate_ring_alarm [caller_id.ring];
        IFEND;

        pmv$activate_ring_alarm [caller_id.ring] := NIL;
      IFEND;
      activate_ring_alarm := (pmv$ring_alarm [alarm_ring] <> NIL);
    ELSE
      activate_ring_alarm := FALSE;
    IFEND;
  PROCEND pmp$activate_ring_alarm;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] pmp$enable_job_free_flag', EJECT ??


{ PURPOSE:
{   The purpose of this request is to call syp$enable_job_free_flag.

{ NOTE:
{   This is only called from PMM$TASKING_HELPER_PROCEDURES which is assembler.

  PROCEDURE [XDCL, #GATE] pmp$enable_job_free_flag;

    osp$verify_system_privilege;
    syp$enable_job_free_flag;
  PROCEND pmp$enable_job_free_flag;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] pmp$get_delayed_condition', EJECT ??
*copy pmh$get_delayed_condition

  PROCEDURE [XDCL, #GATE] pmp$get_delayed_condition
    (VAR delayed_condition: pmt$delayed_condition;
     VAR condition_present: boolean;
     VAR another_condition_present: boolean);

    VAR
      traps: 0 .. 3,
      free_dc: ^ {BOUND} pmt$delayed_condition,
      caller_id: ost$caller_identifier;

    #CALLER_ID (caller_id);
    osp$verify_system_privilege;
    i#disable_traps (traps);
    IF (pmv$ring_alarm [caller_id.ring] <> NIL) THEN
      free_dc := pmv$ring_alarm [caller_id.ring];
      pmv$ring_alarm [caller_id.ring] := pmv$ring_alarm [caller_id.ring]^.next_delayed_condition;
      i#restore_traps (traps);
      delayed_condition := free_dc^;
      condition_present := TRUE;
      another_condition_present := (pmv$ring_alarm [caller_id.ring] <> NIL);
      FREE free_dc IN osv$task_private_heap^;
    ELSE
      i#restore_traps (traps);
      condition_present := FALSE;
      another_condition_present := FALSE;
    IFEND;
  PROCEND pmp$get_delayed_condition;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] pmp$post_delayed_condition', EJECT ??
*copy pmh$post_delayed_condition

  PROCEDURE [XDCL, #GATE] pmp$post_delayed_condition
    (    delayed_condition: ^pmt$delayed_condition;
     VAR status: ost$status);

    VAR
      dc: ^ {BOUND} pmt$delayed_condition,
      caller_id: ost$caller_identifier;

    #CALLER_ID (caller_id);
    status.normal := TRUE;
    osp$verify_system_privilege;
    ALLOCATE dc {: [delayed_condition^.delayed_condition]} IN osv$task_private_heap^;
    CASE delayed_condition^.delayed_condition OF
    = debug =
      dc^.delayed_condition := debug;
      dc^.condition := delayed_condition^.condition;
      dc^.condition_save_area := delayed_condition^.condition_save_area;
      dc^.debug_index := delayed_condition^.debug_index;
    = job_resource =
      dc^.delayed_condition := job_resource;
      dc^.job_resource_condition := delayed_condition^.job_resource_condition;
    = interactive =
      dc^.delayed_condition := interactive;
      dc^.interactive_condition := delayed_condition^.interactive_condition;
    = process_interval_timer =
      dc^.delayed_condition := process_interval_timer;
    = user_condition =
      dc^ := delayed_condition^;
    CASEND;
    dc^.next_delayed_condition := pmv$activate_ring_alarm [caller_id.ring];
    pmv$activate_ring_alarm [caller_id.ring] := dc;
  PROCEND pmp$post_delayed_condition;
?? OLDTITLE ??
?? OLDTITLE ??
MODEND pmm$manage_condition_stacks;
