?? RIGHT := 110 ??
MODULE iim$break_handler;
{
{  PURPOSE:
{        The purpose of this module is to handle interactive conditions.

  TYPE
    iit$task_queued_conditions = SET of ifc$pause_break .. ifc$job_reconnect;

  VAR
    iiv$task_queued_conditions: [XDCL, oss$task_private] iit$task_queued_conditions :=
      $iit$task_queued_conditions [],
    initial_put_info: [READ, oss$job_paged_literal] iit$task_put_info := [1, 0,
      amc$terminate, FALSE, FALSE, FALSE, 0];

?? PUSH (LISTEXT := ON) ??
*copyc ift$condition_codes
*copyc ifc$interrupt
*copyc iik$keypoints
*copyc ife$error_codes
*copyc tmc$signal_identifiers
*copyc iit$interactive_signal_type
*copyc iit$connection_description
*copyc iip$add_sender
*copyc iip$build_super_msg_skeleton
*copyc iip$clear_lock
*copyc iip$delete_queue_entry
*copyc iip$delete_queue_entry
*copyc iip$flush
*copyc iip$free_queue_entry
*copyc iiv$interactive_terminated
*copyc iiv$output
*copyc iip$sign_on
*copyc iip$sign_off
*copyc iip$set_lock
*copyc iip$send_to_pass_on
*copyc iip$receive_from_pass_on
*copyc iip$report_status_error
*copyc iiv$int_task_open_file_count
*copyc iiv$connection_desc_ptr
*copyc jme$queued_file_conditions
*copyc tmc$wait_times
*copyc pmp$long_term_wait
*copyc pmp$ready_task
*copyc pmp$send_signal
*copyc osv$job_pageable_heap
*copyc oss$job_paged_literal
*copyc oss$task_private
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc osv$task_private_heap
*copyc osp$test_sig_lock
*copyc osp$test_set_job_sig_lock
*copyc osp$clear_job_signature_lock
*copyc pmp$log
*copyc osp$system_error
*copyc jmp$system_job
*copyc pmt$condition_information
*copyc pmt$condition
*copyc pmp$begin_timesharing_condition
*copyc pmp$begin_timesharing_handler
*copyc pmp$disestablish_cond_handler
*copyc pmp$enable_timesharing_io
*copyc pmp$enable_ts_io_in_tasks
*copyc pmp$end_timesharing_handler
*copyc pmp$establish_condition_handler
*copyc pmp$ts_task_io_enabled
*copyc pmp$zero_ts_conditions_in_task
*copyc pmp$continue_to_cause
*copyc jmv$jcb
*copyc jmv$terminal_io_disabled
*copyc pmv$task_execution_phase
PROCEDURE [XREF] iip$complete_reconnect;
PROCEDURE [XREF] iip$complete_disconnect;
?? POP ??

?? TITLE := ' PROCEDURE  iip$begin_condition ', EJECT ??

  PROCEDURE [XDCL] iip$begin_condition (condition: ift$interactive_condition;
    VAR status: ost$status);

    VAR
      isig: ^iit$interactive_signal,
      signal: pmt$signal,
      tqc: ift$interactive_condition,
      i,
      mult,
      igtid: integer,
      iiv$break_application_name: mlt$application_name,
      dqlock: boolean,
      ls: ost$signature_lock_status,
      gtid: ost$global_task_id,
      iiv$abort_get: [XREF] boolean,
      iiv$job_output: [XREF] ^seq(*),
      osm: iit$output_supervisory_message;

    IF iiv$task_condition_in_progress THEN
      pmp$log ('IF: condition queued within task already processing condition',
            status);
      iiv$task_queued_conditions := iiv$task_queued_conditions +
        $iit$task_queued_conditions [condition];
      RETURN;
    IFEND;

    status.normal := TRUE;
    iiv$task_condition_in_progress := TRUE;
    dqlock := TRUE;

{ Enable this task to do IO on the connection.

    pmp$enable_timesharing_io;
    pmp$begin_timesharing_condition;

    osp$test_sig_lock (iiv$get_lock, ls);
    IF ls = osc$sls_locked_by_current_task THEN
{ do nothing ... continue condition processing
    ELSE
      IF ls = osc$sls_locked_by_another_task THEN
        igtid := iiv$get_lock.lock_id;

      /assemble_gtid/
        BEGIN
          mult := 1;
          FOR i := 1 TO #SIZE (gtid.seqno) DO
            mult := mult * 256;
          FOREND;

          IF (igtid DIV mult) > UPPERVALUE (gtid.index) THEN
            EXIT /assemble_gtid/;
          IFEND;
          gtid.index := igtid DIV mult;
          IF (igtid MOD mult) > UPPERVALUE (gtid.seqno) THEN
            EXIT /assemble_gtid/;
          IFEND;
          gtid.seqno := igtid MOD mult;
          iiv$abort_get := TRUE;
          pmp$ready_task (gtid, status);
        END /assemble_gtid/;
      IFEND;

{ wait for any 'get' to clear

      iip$set_lock (iiv$get_lock, osc$wait, status);
      iiv$get_info.position_in_block := 1;
      iiv$get_info.file_position := amc$eor;
      iiv$get_info.cancel_input := FALSE;
      iip$clear_lock (iiv$get_lock, status);
    IFEND;

    osp$test_sig_lock (iiv$downline_queue_lock, ls);
    IF ls = osc$sls_locked_by_current_task THEN
      dqlock := FALSE;
{ do nothing ... continue condition processing
    ELSE
      IF ls = osc$sls_locked_by_another_task THEN
        igtid := iiv$downline_queue_lock.lock_id;

      /asm_gtid_dql/
        BEGIN
          mult := 1;
          FOR i := 1 TO #SIZE (gtid.seqno) DO
            mult := mult * 256;
          FOREND;

          IF (igtid DIV mult) > UPPERVALUE (gtid.index) THEN
            EXIT /asm_gtid_dql/;
          IFEND;
          gtid.index := igtid DIV mult;
          IF (igtid MOD mult) > UPPERVALUE (gtid.seqno) THEN
            EXIT /asm_gtid_dql/;
          IFEND;
          gtid.seqno := igtid MOD mult;
          pmp$ready_task (gtid, status);
        END /asm_gtid_dql/;
      IFEND;
    IFEND;

{ lock downline/repeat queues and adjust their contents based on the abn
{ found in the nam break sm.

    IF dqlock THEN
      iip$set_lock (iiv$downline_queue_lock, osc$wait, status);
    IFEND;
    reset iiv$output;
    reset iiv$job_output;
    iiv$downline_queue_count := 0;
    iiv$put_info := initial_put_info;
    IF dqlock THEN
      iip$clear_lock (iiv$downline_queue_lock, status);
    IFEND;


{ discard any typed ahead input - this must be done before the reset is sent

    IF (condition = ifc$pause_break) OR (condition = ifc$terminate_break) THEN
      iip$discard_typed_ahead_input (FALSE);
    IFEND;

{ enable terminal (for this task)


    IF (condition = ifc$pause_break) OR (condition = ifc$terminate_break) THEN

{ restart terminal

      iip$sign_on (iiv$break_application_name, status);
      IF NOT status.normal THEN
        osp$system_error ('IF - break cant signon', ^status);
      IFEND;
      iip$add_sender (iiv$break_application_name, status);


      iip$build_super_msg_skeleton (#LOC (osm), iic$sm_resume_output_mark,
            iic$l_resume_output_mark);
      osm.header.address := iiv$job_connection;
      osm.header.character_type := iic$8_bit_characters;
      osm.header.block_number := 0;
      iip$send_to_pass_on (iiv$break_application_name, #LOC (osm),
            (iic$l_resume_output_mark + 1) * 8, iic$output_data_message +
            iiv$job_connection, status);


{ send intr/resp here

      iip$build_super_msg_skeleton (#LOC (osm), iic$sm_interrupt_response,
            iic$l_interrupt_response);
      osm.interrupt_response.alpha := CHR (0);
      osm.interrupt_response.connection_number := iiv$job_connection;
      osm.interrupt_response.fill1 := 0;
      iip$send_to_pass_on (iiv$break_application_name, #LOC (osm),
            (iic$l_interrupt_response + 1) * 8, iic$output_supervisory_message,
            status);
      IF NOT status.normal THEN
        iip$report_status_error (status, 'send to passon');
      IFEND;
      iip$sign_off (iiv$break_application_name, status);
    ELSEIF condition = ifc$terminal_connection_broken THEN
      iip$complete_disconnect;
    ELSEIF condition = ifc$job_reconnect THEN
      iip$complete_reconnect;
    IFEND;

    iiv$task_condition_in_progress := FALSE;

    WHILE iiv$task_queued_conditions <> $iit$task_queued_conditions [] DO
      FOR tqc := ifc$pause_break TO ifc$job_reconnect DO
        IF tqc IN iiv$task_queued_conditions THEN
          iiv$task_queued_conditions := iiv$task_queued_conditions -
            $iit$task_queued_conditions [tqc];
          iip$begin_condition (tqc, status);
        IFEND;
      FOREND;
    WHILEND;

    signal.identifier := ifc$signal_id;
    isig := #LOC (signal.contents);
    isig^ := iic$resume_task;
    pmp$send_signal (iiv$job_monitor_task_id, signal, status);


  PROCEND iip$begin_condition;
?? TITLE := ' PROCEDURE [XDCL, #GATE] iip$discard_typed_ahead_input', EJECT ??

  PROCEDURE [XDCL, #GATE] iip$discard_typed_ahead_input (save: boolean);

    VAR
      status: ost$status,
    locked: boolean,
      appl: mlt$application_name,
      ls: ost$signature_lock_status,
      osm: iit$output_supervisory_message,
      upline_data: iit$input_supervisory_message,
      upline_length: mlt$message_length;

    osp$test_sig_lock (iiv$get_lock, ls);
    IF ls <> osc$sls_locked_by_current_task THEN
      osp$test_set_job_sig_lock (iiv$get_lock, locked);
      IF NOT locked THEN
        { cannot get lock - skip it.
        RETURN;
      IFEND;
    IFEND;
    iip$sign_on (appl, status);
    IF NOT status.normal THEN
      IF ls <> osc$sls_locked_by_current_task THEN
        osp$clear_job_signature_lock (iiv$get_lock);
      IFEND;
      RETURN;
    IFEND;
    iip$add_sender (appl, status);
    IF NOT status.normal THEN
      IF ls <> osc$sls_locked_by_current_task THEN
        osp$clear_job_signature_lock (iiv$get_lock);
      IFEND;
      iip$sign_off (appl, status);
      RETURN;
    IFEND;


{ fetch and discard all typed ahead input
    iip$build_super_msg_skeleton (#LOC (osm), iic$sm_read_request,
          iic$l_read_request);
    osm.read_request.connection_number := iiv$job_connection;
    osm.read_request.begin_absentee := FALSE; {** note **}
    osm.read_request.notify_if_absentee_started := FALSE;

  /fetch_type_ahead/
    BEGIN
      REPEAT
        iip$send_to_pass_on (appl, #LOC (osm), (iic$l_read_request + 1) * 8,
              iic$output_supervisory_message, status);
        IF NOT status.normal THEN
          EXIT /fetch_type_ahead/;
        IFEND;
        iip$receive_from_pass_on (appl, #LOC (upline_data), #SIZE
              (upline_data), upline_length, status);
        IF NOT status.normal THEN
          EXIT /fetch_type_ahead/;
        IFEND;
      UNTIL ((upline_data.header.block_type = iic$supervisory_block) AND
            ((upline_data.message_type = iic$sm_break_indication_mark) OR
            (upline_data.message_type = iic$sm_read_rejected))) OR
            (upline_data.header.block_type = iic$null_block);
    END /fetch_type_ahead/;

    IF ls <> osc$sls_locked_by_current_task THEN
      osp$clear_job_signature_lock (iiv$get_lock);
    IFEND;
    iip$sign_off (appl, status);

  PROCEND iip$discard_typed_ahead_input;
?? TITLE := ' PROCEDURE [XDCL, #gate] iip$check_for_condition', EJECT ??

  PROCEDURE [XDCL, #GATE] iip$check_for_condition (VAR status: ost$status);

    VAR
      signal: pmt$signal,
      isig: ^iit$interactive_signal,
      start: [STATIC] integer,
      time: [STATIC] integer := 0,
      eh: pmt$established_handler;

?? NEWTITLE := 'PROCEDURE handle_break', EJECT ??

    PROCEDURE handle_break (cond: pmt$condition;
          cd: ^pmt$condition_information;
          sa: ^ost$stack_frame_save_area;
      VAR ch_status: ost$status);

      VAR
        local_status: ost$status;

{ return to screen with abnormal status

      time := 0;
      pmp$continue_to_cause (pmc$execute_standard_procedure, local_status);

      CASE cond.interactive_condition OF
      = ifc$pause_break =
        osp$set_status_abnormal (ifc$interactive_facility_id,
              ife$pause_break_received, '', status);
      = ifc$terminate_break =
        osp$set_status_abnormal (ifc$interactive_facility_id,
              ife$terminate_break_received, '', status);
      = ifc$terminal_connection_broken =
        osp$set_status_abnormal (ifc$interactive_facility_id,
              ife$connection_break_disconnect, '', status);
      = ifc$job_reconnect =
        osp$set_status_abnormal (ifc$interactive_facility_id,
              ife$terminal_reconnected_to_job, '', status);
      ELSE
        osp$set_status_abnormal (ifc$interactive_facility_id, 0,
          'unknown interactive condition encountered', status);
      CASEND;
      EXIT iip$check_for_condition;

    PROCEND handle_break;
?? OLDTITLE ??
?? EJECT ??

    IF jmv$terminal_io_disabled THEN
      osp$set_status_condition (jme$job_is_in_termination, status);
      RETURN;
    IFEND;

    IF (pmv$task_execution_phase > pmc$task_executing) THEN
      osp$set_status_condition (jme$task_is_in_termination, status);
      RETURN;
    IFEND;

    IF iiv$interactive_terminated THEN
      {Ignore all conditions if terminating.
      status.normal := TRUE;
      RETURN;
    IFEND;

    IF iiv$job_suspended THEN
      pmp$establish_condition_handler (iiv$condition_descriptor, ^handle_break,
            ^ eh, status);
      pmp$log (' interactive timeout begins', status);

{ note that time and start are job environment variables and will
{ be used by any task executing this code.

      IF time = 0 THEN
        start := #free_running_clock (0);
        time := jmv$jcb.detached_job_wait_time * 1000;
      IFEND;

    /check_timeout/
      BEGIN

      /timeout/
        WHILE time > 0 DO
          pmp$long_term_wait (time, time);
          IF NOT iiv$job_suspended THEN

{ reconnected ....

            time := 0;
            EXIT /check_timeout/;
          IFEND;
          IF jmv$jcb.detached_job_wait_time <> jmc$unlimited_det_job_wait_time THEN
            time := (jmv$jcb.detached_job_wait_time * 1000) - ((#free_running_clock (0) -
                  start) DIV 1000);
          IFEND;
        WHILEND /timeout/;

{ signal jmtr to exit

        signal.identifier := ifc$signal_id;
        isig := #LOC (signal.contents);
        isig^ := iic$jmtr_start_timeout;
        pmp$send_signal (iiv$job_monitor_task_id, signal, status);


{ Return with abnormal status to the user

        osp$set_status_abnormal ('JM', jme$job_is_in_termination, '', status);
        RETURN;
      END /check_timeout/;
    IFEND;

    IF NOT pmp$ts_task_io_enabled () THEN
      pmp$establish_condition_handler (iiv$condition_descriptor, ^handle_break,
            ^ eh, status);
      WHILE NOT pmp$ts_task_io_enabled () DO
        pmp$long_term_wait (tmc$infinite_wait, 100000000);
      WHILEND;
      {Force a return to the screen so this routine will be recalled
      {and all previous conditions will be checked again!!!! (like disconnect)
      osp$set_status_abnormal (ifc$interactive_facility_id,
            ife$pause_break_received, '', status);
      RETURN;
    IFEND;
    status.normal := TRUE;

  PROCEND iip$check_for_condition;
?? TITLE := ' PROCEDURE iip$discard_suspended_output', EJECT ??

  PROCEDURE [XDCL, #GATE] iip$discard_suspended_output;
  PROCEND iip$discard_suspended_output;
MODEND iim$break_handler
