?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE: Program Control - Preemptive Communications' ??
MODULE tmm$wait;

{ PURPOSE:
{   The purpose of this module is to package contained procedures so
{   that they execute with the privileges necessary to read the structures
{   in the execution control block that support signals and system flags.
{
{ DESIGN:
{   The procedures contained in the module have an execution bracket
{   of 2, 3 and a call bracket of 13.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc osc$processor_defined_registers
*copyc oss$job_paged_literal
*copyc ost$caller_identifier
*copyc ost$execution_control_block
*copyc pmt$task_control_block
*copyc tmc$execution_ring_constants
*copyc tmt$allocated_execution_rings
*copyc tmt$preempted_reason
*copyc tmt$rb_wait
?? POP ??
*copyc i#call_monitor
*copyc osp$establish_block_exit_hndlr
*copyc osp$verify_system_privilege
*copyc pmp$find_executing_task_xcb
*copyc tmp$allocate_execution_rings
*copyc tmp$clear_wait_inhibited
*copyc tmp$dispose_of_ring2_flags
*copyc tmp$dispose_of_ring2_signals
*copyc tmp$dispose_of_ring3_flags
*copyc tmp$dispose_of_ring3_signals
*copyc tmv$null_global_task_id
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??

  TYPE
    valid_wait_reasons = set of tmt$preempted_reason;

  VAR
    valid_reasons: [STATIC, READ, oss$job_paged_literal] valid_wait_reasons := $valid_wait_reasons
          [tmc$wait, tmc$long_term_wait];

?? OLDTITLE ??
?? NEWTITLE := 'dispose_of_signals_flags' ??

  PROCEDURE dispose_of_signals_flags
    (    wait_reason: tmc$wait .. tmc$long_term_wait;
     VAR disposed: boolean);

    TYPE
      signals_present = set of tmt$signal_buffers;

    VAR
      allocated_flag_execution_rings: tmt$allocated_execution_rings,
      allocated_signl_execution_rings: tmt$allocated_execution_rings,
      executing_ring: ost$ring,
      execution_ring: tmt$handler_execution_ring,
      ignore_status: ost$status,
      signals_to_process: ^signals_present,
      tcb_p: ^pmt$task_control_block,
      xcb_p: ^ost$execution_control_block;

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

{ PURPOSE:
{   This procedure ensures that all preemptive communications are processed
{   before a nonlocal exit is premitted to complete or the task is permitted
{   to terminate.

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


      status.normal := TRUE;
      dispose_of_signals_flags (wait_reason, disposed);
    PROCEND dispose_of_nonlocal_exit;
?? OLDTITLE ??
?? EJECT ??

    disposed := FALSE;
    pmp$find_executing_task_xcb (xcb_p);
    tcb_p := xcb_p^.task_control_block;
    signals_to_process := #LOC (xcb_p^.signals.present);
    IF (signals_to_process^ <> $signals_present []) OR (tcb_p^.task_local_signal_list.delink <> NIL) OR
          (xcb_p^.system_flags <> $tmt$system_flags []) THEN
      osp$establish_block_exit_hndlr (^dispose_of_nonlocal_exit);
      IF (signals_to_process^ <> $signals_present []) OR (tcb_p^.task_local_signal_list.delink <> NIL) THEN
        tmp$allocate_execution_rings (#RING (^executing_ring), wait_reason, tmc$signal,
              allocated_signl_execution_rings);
        FOR execution_ring := tmc$lowest_signal_flag_ring TO tmc$highest_signal_flag_ring DO
          IF execution_ring IN allocated_signl_execution_rings THEN
            CASE execution_ring OF
            = tmc$task_monitor2_ring =
              tmp$dispose_of_ring2_signals;
            = tmc$task_services_ring =
              tmp$dispose_of_ring3_signals;
            CASEND;
            disposed := TRUE;
          IFEND;
        FOREND;
      IFEND;
      IF (xcb_p^.system_flags <> $tmt$system_flags []) THEN
        tmp$allocate_execution_rings (#RING (^executing_ring), wait_reason, tmc$system_flag,
              allocated_flag_execution_rings);
        FOR execution_ring := tmc$lowest_signal_flag_ring TO tmc$highest_signal_flag_ring DO
          IF execution_ring IN allocated_flag_execution_rings THEN
            CASE execution_ring OF
            = tmc$task_monitor2_ring =
              tmp$dispose_of_ring2_flags;
            = tmc$task_services_ring =
              tmp$dispose_of_ring3_flags;
            CASEND;
            disposed := TRUE;
          IFEND;
        FOREND;
      IFEND;
      #WRITE_REGISTER (osc$pr_clear_critical_frame, 0);
    IFEND;
  PROCEND dispose_of_signals_flags;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] tmp$dispose_of_signals_flags', EJECT ??
*copy tmh$dispose_of_signals_flags

  PROCEDURE [XDCL] tmp$dispose_of_signals_flags
    (    preemptive_reason: tmt$preempted_reason);

    VAR
      disposed: boolean;

    IF (preemptive_reason IN valid_reasons) THEN
      dispose_of_signals_flags (preemptive_reason, disposed);
    IFEND;
  PROCEND tmp$dispose_of_signals_flags;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] tmp$wait', EJECT ??

{ PURPOSE:
{  The purpose of this request is to support the pmp$wait and pmp$long_term_wait requests - processing
{  signals and system flags as appropriate.

  PROCEDURE [XDCL, #GATE] tmp$wait
    (    global_taskid: ost$global_task_id;
         wait_reason: tmc$wait .. tmc$long_term_wait;
         milliseconds: 0 .. 0ffffffffffff(16);
         expected_milliseconds: 0 .. 0ffffffffffff(16));

    VAR
      current_time: ost$free_running_clock,
      disposed: boolean,
      ignore_status: ost$status,
      wait: tmt$rb_wait,
      wait_inhibited: boolean;

    osp$verify_system_privilege;
    current_time := #FREE_RUNNING_CLOCK (0);
    IF (wait_reason IN valid_reasons) THEN
      dispose_of_signals_flags (wait_reason, disposed);

{ If no signal or flags were present - it is okay to go into wait.

      IF NOT disposed THEN
        wait.reqcode := syc$rc_wait;
        IF (((milliseconds * 1000) + current_time) > UPPERVALUE (ost$free_running_clock)) THEN
          wait.requested_wait_time := UPPERVALUE (ost$free_running_clock);
        ELSE
          wait.requested_wait_time := (milliseconds * 1000) + current_time;
        IFEND;

        IF (((expected_milliseconds * 1000) + current_time) > UPPERVALUE (ost$free_running_clock)) THEN
          wait.expected_wait_time := UPPERVALUE (ost$free_running_clock);
        ELSE
          wait.expected_wait_time := expected_milliseconds * 1000;
        IFEND;
        wait.global_taskid := global_taskid;

        i#call_monitor (#LOC (wait), #SIZE (wait));
        dispose_of_signals_flags (wait_reason, disposed);
      ELSE

{ Make sure that wait inhibited is cleared before exit.

        tmp$clear_wait_inhibited (wait_inhibited);
      IFEND;
    IFEND;
  PROCEND tmp$wait;
?? OLDTITLE ??
MODEND tmm$wait;
