?? RIGHT := 110 ??
?? TITLE := 'NOS/VE: job recovery r3' ??
MODULE sym$job_recovery_r3;
?? PUSH (LISTEXT := ON) ??
*copyc cml$job_recovery_failure
*copyc cml$job_recovery_totals
*copyc fme$file_management_errors
*copyc iit$connection_description
*copyc jmc$maximum_job_count
*copyc jmc$special_dispatch_priorities
*copyc jmc$system_family
*copyc jml$user_id
*copyc jmt$ijl_ordinal
*copyc jmt$initiated_job_list_entry
*copyc jmt$job_class
*copyc jmt$job_count_range
*copyc jmt$job_scheduler_event
*copyc jmt$job_system_id
*copyc jmt$swap_file_recovery_list
*copyc jmt$system_supplied_name
*copyc oft$designer_screens_types
*copyc osc$timesharing
*copyc ose$job_recovery_exceptions
*copyc oss$task_private
*copyc oss$task_shared
*copyc ost$caller_identifier
*copyc ost$system_flag
*copyc pfe$internal_error_conditions
*copyc pmt$program_parameters
*copyc sye$job_recovery_conditions
*copyc syt$job_recovery_step
*copyc tmt$change_priority_origin
?? POP ??
?? NEWTITLE := '  Global Declarations Referenced by This Module', EJECT ??
*copyc amp$return
*copyc clp$get_value
*copyc clp$put_job_output
*copyc clp$scan_command_line
*copyc clp$scan_parameter_list
*copyc cmp$recover_subsystem_io_table
*copyc dfp$recover_jobs_servers
*copyc dmp$fetch_eoi
*copyc dmv$display_recovery_messages
*copyc dmv$ds_msg_update_interval
*copyc dsp$log_job_recovery_statistics
*copyc gfp$get_segment_sfid
*copyc fmp$ln_open_chapter
*copyc fmp$recover_job_files
*copyc iip$terminate_disconnected_job
*copyc jmp$change_dispatching_prior_r1
*copyc jmp$emit_job_history_statistics
*copyc jmp$get_ijle_p
*copyc jmp$handle_ts_system_disconnect
*copyc jmp$job_monitor_xcb
*copyc jmp$rebuild_executing_job
*copyc jmp$record_job_attributes
*copyc jmp$system_job
*copyc mmp$close_segment
*copyc mmp$create_scratch_segment
*copyc mmp$delete_scratch_segment
*copyc mmp$free_pages
*copyc mmp$get_max_sdt_sdtx_pointer
*copyc mmp$get_sdtx_entry_p
*copyc mmp$set_access_selections
*copyc nlp$recover_task_activity
*copyc ofp$display_status_message
*copyc ofp$purge_incremental_data
*copyc osp$generate_log_message
*copyc osp$generate_message
*copyc osp$get_status_condition_name
*copyc osp$disestablish_cond_handler
*copyc osp$establish_condition_handler
*copyc osp$log_unformatted_status
*copyc osp$set_status_abnormal
*copyc osp$set_status_from_condition
*copyc osp$system_error
*copyc osp$verify_system_privilege
*copyc pfp$get_multi_item_info
*copyc pfp$find_next_info_record
*copyc pfp$find_directory_array
*copyc pfp$restricted_attach
*copyc pfp$overhaul_catalog
*copyc pfp$purge
*copyc pmp$cause_task_condition
*copyc pmp$continue_to_cause
*copyc pmp$delay
*copyc pmp$exit
*copyc pmp$find_executing_task_xcb
*copyc pmp$get_job_mode
*copyc pmp$get_legible_date_time
*copyc pmp$get_unique_name
*copyc pmp$log_ascii
*copyc pmp$wait
*copyc pmp$zero_out_table
*copyc qfp$expand_kjl
*copyc qfp$relink_kjl_application
*copyc qfp$relink_kjl_client
*copyc qfp$relink_kjl_entry
*copyc qfp$relink_kjl_server
*copyc rfp$recover_task_activity
*copyc sfp$emit_statistic
*copyc syp$increment_avt_r1
*copyc syp$increment_file_rcv_failure
*copyc syp$job_recovery_from_image
*copyc syp$log_recovery_failure
*copyc syp$process_job_rcv_failure
*copyc syp$recover_job_r1
*copyc jmv$executing_within_system_job
*copyc jmv$ijl_p
*copyc jmv$jcb
*copyc jmv$job_attributes
*copyc jmv$job_class_table_p
*copyc jmv$job_history_active
*copyc jmv$job_recovery_information_p
*copyc jmv$kjl_p
*copyc jmv$service_classes
*copyc osv$mainframe_wired_heap
*copyc osv$page_size
*copyc osv$task_shared_heap
*copyc osv$task_private_heap
*copyc qfv$current_kjl_limit
*copyc rfv$job_entry_pointer
*copyc syv$failure_reason_p
*copyc syv$file_rcv_failure_count
*copyc syv$job_recovery_option
*copyc syv$job_recovery_step
*copyc syv$recovering_job_count
*copyc syv$recovery_failure_count
*copyc syv$test_jr_job
?? TITLE := '  Global Declarations Referenced ONLY by This Module', EJECT ??

{ The following xrefs are ONLY used in sym$job_recovery_r3, hence, no XREF decks.

  TYPE
    zzzz = (job, system);

  PROCEDURE [XREF] syp$set_job_recovery_test
    (    t: zzzz;
         option: 0 .. 255);

  PROCEDURE [XREF] syp$clear_job_recovery_test
    (    t: zzzz;
         option: 0 .. 255);

  PROCEDURE [XREF] syp$jt_recovery_complete
    (VAR status: ost$status);

  PROCEDURE [XREF] syp$complete_job_recovery;

  PROCEDURE [XREF] syp$terminate_unrecovered_job
    (    ijl_ordinal: jmt$ijl_ordinal);

  PROCEDURE [XREF] syp$check_maxaj_and_ready_sched;

  PROCEDURE [XREF] iip$disconnect_job
    (    end_job_connection: boolean;
         start_new_job: boolean;
     VAR status: ost$status);

  PROCEDURE [XREF] syp$recover_volume_file_space;

  PROCEDURE [XREF] syp$begin_job_recovery
    (    buffer_limit: 0 .. jmc$maximum_job_count);

  PROCEDURE [XREF] syp$end_job_recovery;

  PROCEDURE [XREF] syp$decrement_job_task_count;

  PROCEDURE [XREF] syp$init_job_rec_from_image
    (VAR status: ost$status);

  PROCEDURE [XREF] mlp$recover_job_environment
    (VAR status: ost$status);

  VAR
    syv$job_task_count: [XREF] integer,
    syv$job_recovery_wait_time: [XREF] integer;


  VAR
    job_recovery_inhibited: [STATIC, oss$task_shared] boolean := FALSE,
    jobs_recovering_count: [STATIC, oss$task_shared] integer := 0,
    osv$inhibit_job_recovery_count: [XDCL, oss$task_private] integer := 0,
    osv$job_recovery_required: [XDCL, #GATE, oss$task_private] boolean := FALSE,
    osv$job_recovery_alert: [XDCL, #GATE, oss$task_private] boolean := FALSE,
    recovery_termination: [STATIC, oss$task_shared] boolean := FALSE,
    recovered_job_count: [STATIC, oss$task_shared] 0 .. jmc$max_ijl_entries,
    recovered_jobs: [STATIC, oss$task_shared] ^jmt$swap_file_recovery_list := NIL;


?? TITLE := '  PROCEDURE osp$complete_job_recovery', EJECT ??

{ PURPOSE:
{   This procedure is called AFTER pf recovery to complete job recovery functions as follows:
{     - start volume space recovery task

  PROCEDURE [XDCL] osp$complete_job_recovery
    (VAR status: ost$status);

    PROCEDURE ch
      (    condition: pmt$condition;
           cd: ^pmt$condition_information;
           sa: ^ost$stack_frame_save_area;
       VAR ignore: ost$status);

      osp$set_status_from_condition ('OS', condition, sa, status, ignore);
      IF NOT ignore.normal THEN
        status := ignore;
      IFEND;
      EXIT osp$complete_job_recovery;

    PROCEND ch;

    IF NOT jmp$system_job () THEN
      osp$system_error (' malicious user access', NIL);
      RETURN;
    IFEND;

    osp$establish_condition_handler (^ch, FALSE);

    clp$scan_command_line ('EXET SP=OSP$RECOVER_VOLUME_FILE_SPACE LMO=NONE DM=' CAT 'OFF TEL=WARNING TN=RVFS',
          status);
    IF NOT status.normal THEN
      display_status (status);
    IFEND;

    status.normal := TRUE;

  PROCEND osp$complete_job_recovery;
?? TITLE := '  PROCEDURE jmp$find_jsn', EJECT ??

  PROCEDURE jmp$find_jsn
    (    jsn: jmt$system_supplied_name;
     VAR ijle_p: ^jmt$initiated_job_list_entry);

    VAR
      ijl_bn: jmt$ijl_block_number,
      ijl_bi: jmt$ijl_block_index,
      ijl_p: ^jmt$initiated_job_list_entry;

    ijle_p := NIL;

  /scan_ijl_for_jsn/

    FOR ijl_bn := LOWERBOUND (jmv$ijl_p.block_p^) TO jmv$ijl_p.max_block_in_use DO
      IF (jmv$ijl_p.block_p^ [ijl_bn].index_p <> NIL) THEN
        FOR ijl_bi := LOWERVALUE (jmt$ijl_block_index) TO UPPERVALUE (jmt$ijl_block_index) DO
          ijl_p := ^jmv$ijl_p.block_p^ [ijl_bn].index_p^ [ijl_bi];
          IF ijl_p^.system_supplied_name = jsn THEN
            ijle_p := ijl_p;
            RETURN;
          IFEND;
        FOREND;

      IFEND;
    FOREND /scan_ijl_for_jsn/;
  PROCEND jmp$find_jsn;
?? TITLE := '  PROCEDURE osp$recover_volume_file_space', EJECT ??

  PROCEDURE [XDCL, #GATE] osp$recover_volume_file_space
    (    p: pmt$program_parameters;
     VAR status: ost$status);

    VAR
      ijlep: ^jmt$initiated_job_list_entry,
      str: string (255),
      i,
      strl: integer;

    IF NOT jmp$system_job () THEN
      osp$system_error (' malicious user access', NIL);
      RETURN;
    IFEND;

    display (' Recover volume file space task started');
    syp$recover_volume_file_space;

{ Recovering jobs have completed recovery, detach swap files from the
{ system job.  Note special case for jobs that did not recover.  THIS IS IMPORTANT.

    display ('Detaching recovered jobs from system job');

  /detf/
    FOR i := 1 TO recovered_job_count DO
      IF recovered_jobs^ [i].recovery_disposition_available AND
            (recovered_jobs^ [i].job_recovery_disposition = jmc$continue_on_recovery) THEN
        jmp$find_jsn (recovered_jobs^ [i].system_job_name, ijlep);
        IF ijlep <> NIL THEN
          IF ijlep^.job_damaged_during_recovery THEN
            STRINGREP (str, strl, 'Recovered job damaged during recovery: ',
                  recovered_jobs^ [i].system_job_name);
            display (str (1, strl));
            CYCLE /detf/;
          IFEND;
        IFEND;
        STRINGREP (str, strl, 'Recovered job detached: ', recovered_jobs^ [i].system_job_name);
        display (str (1, strl));
        amp$return (recovered_jobs^ [i].local_file_name, status);
        IF NOT status.normal THEN
          display_status (status);
        IFEND;
      IFEND;
    FOREND /detf/;

    IF recovered_job_count <> 0 THEN
      dsp$log_job_recovery_statistics (recovered_job_count, jobs_recovering_count, status);
    IFEND;

    syp$complete_job_recovery;

    IF recovered_jobs <> NIL THEN
      FREE recovered_jobs IN osv$task_shared_heap^;
    IFEND;

  PROCEND osp$recover_volume_file_space;
?? TITLE := '  PROCEDURE osp$recover_executing_jobs', EJECT ??

  PROCEDURE [XDCL] osp$recover_executing_jobs
    (VAR swap_file_recovery_list: ^jmt$swap_file_recovery_list;
     VAR swap_file_recovery_list_count: jmt$job_count_range;
     VAR status: ost$status);

{ This procedure is called BEFORE all of: system commit, pf recovery and start job sched task.
{ It must NOT write into any permanent file catalogs, as the changes are not recoverable.
{ Notes:
{ 1) Swap files are left attached.  This is done so that the sfid will be valid for all
{    swapins done after recovery, but before the job is able to recover the swap file.

    PROCEDURE ch
      (    condition: pmt$condition;
           cd: ^pmt$condition_information;
           sa: ^ost$stack_frame_save_area;
       VAR ignore: ost$status);

      osp$set_status_from_condition ('OS', condition, sa, status, ignore);
      IF NOT ignore.normal THEN
        status := ignore;
      IFEND;
      EXIT osp$recover_executing_jobs;
    PROCEND ch;
?? EJECT ??


    CONST
      second = 1000000;

    VAR
      base: integer,
      clock: integer,
      date: ost$date,
      directory_array_p: pft$p_directory_array,
      display_update_interval: integer,
      group: pft$group,
      ignore_status: ost$status,
      info_record_p: pft$p_info_record,
      init_status: ost$status,
      jsn_index: integer,
      log_msg: string (80),
      msg_len: integer,
      path: array [1 .. 4] of pft$name,
      segment_pointer: amt$segment_pointer,
      sequence_p: ^SEQ ( * ),
      time: ost$time,
      vp: array [1 .. 3] of pft$name;


    IF NOT jmp$system_job () THEN
      osp$system_error (' malicious user access', NIL);
      RETURN;
    IFEND;

    swap_file_recovery_list := NIL;
    swap_file_recovery_list_count := 0;
    init_status.normal := TRUE;

    vp [1] := jmc$system_family;
    vp [2] := jmc$system_user;
    osp$establish_condition_handler (^ch, FALSE);

    CASE syv$job_recovery_option OF
    = syc$jre_enabled =
      syp$init_job_rec_from_image (init_status);
      IF NOT init_status.normal THEN
        display_status (init_status);
        display ('Job recovery disabled by the system');
        log_msg := 'Job recovery disabled by the system.';
        msg_len := 36;
      ELSE
        display ('Job recovery enabled');
      IFEND;

      vp [3] := jmc$job_swap_catalog;
      pfp$overhaul_catalog (vp, $pft$catalog_overhaul_choices [pfc$validate_files], status);
      IF NOT status.normal THEN
        display_status (status);
        RETURN;
      IFEND;
    = syc$jre_command_disabled =
      display ('Job recovery disabled by set_system_attribute command.');
      log_msg := 'Job recovery disabled by set_system_attribute command.';
      msg_len := 54;
    = syc$jre_prior_ds_disabled =
      display ('Job recovery disabled by prior deadstart.');
      log_msg := 'Job recovery disabled by prior deadstart.';
      msg_len := 41;
    = syc$jre_no_image =
      display ('Job recovery disabled because memory image is not available.');
      log_msg := 'Job recovery disabled because memory image is not available.';
      msg_len := 60;
    = syc$jre_different_system =
      display ('Job recovery disabled because a different system is being deadstarted.');
      log_msg := 'Job recovery disabled because a different system is being deadstarted.';
      msg_len := 70;
    = syc$jre_page_size_mismatch =
      display ('Job recovery disabled because a different page size is being used.');
      log_msg := 'Job recovery disabled because a different page size is being used.';
      msg_len := 66;
    ELSE
      display ('Unexpected job recovery option value');
      STRINGREP (log_msg, msg_len, 'Unexpected job recovery option value of ', syv$job_recovery_option);
    CASEND;

    mmp$create_scratch_segment (amc$sequence_pointer, mmc$as_sequential, segment_pointer, status);
    IF NOT status.normal THEN
      display_status (status);
      RETURN;
    IFEND;
    sequence_p := segment_pointer.sequence_pointer;

    group.group_type := pfc$public;
    vp [3] := jmc$job_swap_catalog;
    RESET sequence_p;

    pfp$get_multi_item_info (vp, group, $pft$catalog_info_selections [],
          $pft$file_info_selections [pfc$file_description], sequence_p, status);
    IF NOT status.normal THEN
      display_status (status);
      mmp$delete_scratch_segment (segment_pointer, ignore_status);
      RETURN;
    IFEND;

    RESET sequence_p;
    pfp$find_next_info_record (sequence_p, info_record_p, status);
    IF NOT status.normal THEN
      display_status (status);
      mmp$delete_scratch_segment (segment_pointer, ignore_status);
      RETURN;
    IFEND;

    pfp$find_directory_array (info_record_p, directory_array_p, status);
    IF NOT status.normal THEN
      display_status (status);
      mmp$delete_scratch_segment (segment_pointer, ignore_status);
      RETURN;
    IFEND;

    path [1] := jmc$system_family;
    path [2] := jmc$system_user;

    IF directory_array_p <> NIL THEN
      syp$begin_job_recovery (UPPERBOUND (directory_array_p^));
    ELSE
      syp$begin_job_recovery (0);
    IFEND;

    recovered_job_count := 0;
    IF directory_array_p <> NIL THEN
      IF syv$job_recovery_option <> syc$jre_enabled THEN
        IF NOT init_status.normal THEN
          syp$log_recovery_failure (' SYP$INIT_JOB_REC_FROM_IMAGE failed', init_status);
        IFEND;
        status.normal := TRUE;
        syp$log_recovery_failure (log_msg (1, msg_len), status);
      IFEND;

      base := 0;
      display_update_interval := dmv$ds_msg_update_interval * second;
      IF dmv$display_recovery_messages THEN
        pmp$get_legible_date_time (osc$mdy_date, date, osc$hms_time, time, ignore_status);

        STRINGREP (log_msg, msg_len, '   .. Scanning SWAP File Catalog, ', UPPERBOUND (directory_array_p^),
              ' Swap Files found.   ', time.hms);
        clp$put_job_output (log_msg (1, msg_len), ignore_status);
      IFEND;

      ALLOCATE recovered_jobs: [1 .. UPPERBOUND (directory_array_p^)] IN osv$task_shared_heap^;
      path [3] := jmc$job_swap_catalog;
      FOR jsn_index := LOWERBOUND (directory_array_p^) TO UPPERBOUND (directory_array_p^) DO

        IF dmv$display_recovery_messages THEN
          clock := #FREE_RUNNING_CLOCK (0);
          IF clock > (base + display_update_interval) THEN
            base := clock;
            pmp$get_legible_date_time (osc$mdy_date, date, osc$hms_time, time, ignore_status);
            STRINGREP (log_msg, msg_len, '   .. Reconcile Job ', jsn_index:6, ' JSN=',
                  directory_array_p^ [jsn_index].name (1, 19), ' Recovered: ', syv$recovering_job_count:6,
                  '   ', time.hms);

            clp$put_job_output (log_msg (1, msg_len), ignore_status);
          IFEND;
        IFEND;

        path [4] := directory_array_p^ [jsn_index].name;
        process_swap_file (path);
      FOREND;
    IFEND;
    mmp$delete_scratch_segment (segment_pointer, ignore_status);

    syp$end_job_recovery;
    status.normal := TRUE;

    IF recovered_job_count > 0 THEN
      swap_file_recovery_list := recovered_jobs;
    ELSE
      swap_file_recovery_list := NIL;
    IFEND;
    swap_file_recovery_list_count := recovered_job_count;
    jobs_recovering_count := syv$recovering_job_count;

  PROCEND osp$recover_executing_jobs;
?? TITLE := 'PROCESS_SWAP_FILE', EJECT ??

{  This procedure is called by osp$recover_executing_jobs to process the swap file of the recovering job.

  PROCEDURE process_swap_file
    (    path: array [1 .. 4] of pft$name);

    VAR
      caller_id: ost$caller_identifier,
      cycle_number: fst$cycle_number,
      jcb_found: boolean,
      jcb_search: ^jmt$job_control_block,
      job_recovered: boolean,
      job_recovery_disposition: jmt$job_recovery_disposition,
      oijlep: ^jmt$initiated_job_list_entry,
      pf_cycle: [READ {,oss$job_paged_literal} ] pft$cycle_selector := [pfc$highest_cycle],
      pjcb: ^jmt$job_control_block,
      recovery_disposition_available: boolean,
      sfid: gft$system_file_identifier,
      share: [READ {,oss$job_paged_literal} ] pft$usage_selections := $pft$usage_selections
            [pfc$read, pfc$append, pfc$shorten, pfc$modify],
      sn: jmt$system_supplied_name,
      status: ost$status,
      swap_file_eoi: amt$file_byte_address,
      swap_file_offset: integer,
      swap_file_sfid: gft$system_file_identifier,
      swap_ptr: mmt$segment_pointer,
      uname: ost$name,
      usage: [READ {,oss$job_paged_literal} ] pft$usage_selections := $pft$usage_selections
            [pfc$read, pfc$append, pfc$shorten, pfc$modify];

?? NEWTITLE := 'CH', EJECT ??

    PROCEDURE ch
      (    condition: pmt$condition;
           cd: ^pmt$condition_information;
           sa: ^ost$stack_frame_save_area;
       VAR ignore: ost$status);

      osp$set_status_from_condition ('OS', condition, sa, status, ignore);
      IF NOT ignore.normal THEN
        status := ignore;
      IFEND;
      amp$return (uname, ignore);
      display_and_log_status (status, sn);

      EXIT process_swap_file;

    PROCEND ch;
?? OLDTITLE??
?? EJECT ??

    pmp$get_unique_name (uname, status);

    job_recovered := FALSE;
    recovery_disposition_available := FALSE;
    job_recovery_disposition := jmc$terminate_on_recovery;
    sn := path [4];
    #SPOIL (sn);
    osp$establish_condition_handler (^ch, FALSE);

  /file_attached/
    BEGIN
      IF syv$job_recovery_option <> syc$jre_enabled THEN

{ skip recovery
        IF jmv$job_history_active THEN
          jmp$emit_job_history_statistics (jml$non_recovery_of_job, osc$null_name, sn,
                jmc$blank_system_supplied_name, NIL, NIL, 'sye$job_recovery_disabled      ',
                jmc$blank_system_supplied_name, status);
        IFEND;
        EXIT /file_attached/;
      IFEND;

      pfp$restricted_attach (uname, path, pf_cycle, osc$null_name, usage, share, cycle_number, status);
      IF NOT status.normal THEN
        display_and_log_status (status, sn);
        syp$log_recovery_failure (' Attach of swap file failed', status);
        EXIT /file_attached/;
      IFEND;
      #CALLER_ID (caller_id);
      fmp$ln_open_chapter (uname, 0, caller_id.ring, NIL, mmc$cell_pointer, swap_ptr, status);
      IF NOT status.normal THEN
        display_and_log_status (status, sn);
        syp$log_recovery_failure (' Open of swap file failed', status);
        EXIT /file_attached/;
      IFEND;

    /file_open/
      BEGIN
        mmp$set_access_selections (swap_ptr.cell_pointer, mmc$as_sequential, status);
        IF NOT status.normal THEN
          display_and_log_status (status, sn);
        IFEND;
        syp$job_recovery_from_image (swap_ptr.cell_pointer, sn, oijlep, recovery_disposition_available,
              job_recovery_disposition, status);
        IF NOT status.normal THEN
          display_and_log_status (status, sn);
          syp$log_recovery_failure (' Job recovery from image failed', status);
          EXIT /file_open/;
        IFEND;
        mmp$set_access_selections (swap_ptr.cell_pointer, mmc$as_random, status);
        IF NOT status.normal THEN
          display_and_log_status (status, sn);
        IFEND;
        pjcb := swap_ptr.cell_pointer;
        jcb_found := FALSE;
        swap_file_offset := 0;
        gfp$get_segment_sfid (swap_ptr.cell_pointer, swap_file_sfid, status);
        dmp$fetch_eoi (swap_file_sfid, swap_file_eoi, status);
        WHILE NOT jcb_found DO
          jcb_search := #ADDRESS (1, #SEGMENT (swap_ptr.cell_pointer), swap_file_offset);
          IF jcb_search^.jcb_identifier = 0FF00(16) THEN
            pjcb := jcb_search;
            jcb_found := TRUE;
          ELSE
            swap_file_offset := swap_file_offset + osv$page_size;
            IF swap_file_offset > swap_file_eoi THEN
              osp$set_status_abnormal ('SY', sye$unable_to_locate_jcb, '', status);
              display_and_log_status (status, sn);
              syp$log_recovery_failure (' Unable to locate jcb', status);
              EXIT /file_open/;
            IFEND;
          IFEND;
        WHILEND;

{ Validate the job's Job Control Block (JCB) as best as possible

        IF (pjcb^.system_name <> sn) OR (pjcb^.job_id = jmc$kjl_undefined_index) OR
              (pjcb^.job_id > UPPERBOUND (jmv$kjl_p^)) THEN
          osp$set_status_abnormal ('SY', sye$job_damaged, '', status);
          display_and_log_status (status, sn);
          syp$log_recovery_failure (' JCB is damaged', status);
          EXIT /file_open/;
        IFEND;

        WHILE pjcb^.job_id > qfv$current_kjl_limit DO
          qfp$expand_kjl;
        WHILEND;

{ Verify that the job's entry is available in the KJL.

        IF jmv$kjl_p^ [pjcb^.job_id].entry_kind <> jmc$kjl_unused_entry THEN
          osp$set_status_abnormal ('SY', sye$job_damaged, '', status);
          display_and_log_status (status, sn);
          syp$log_recovery_failure (' Job not in KJL', status);
          EXIT /file_open/;
        IFEND;

        syp$recover_job_r1 (swap_ptr.cell_pointer, pjcb, oijlep, recovery_disposition_available,
              job_recovery_disposition, status);
        IF NOT status.normal THEN
          display_and_log_status (status, sn);
          syp$log_recovery_failure (' Syp$recover_job_r1 failed', status);
          EXIT /file_open/;
        IFEND;

        jmp$rebuild_executing_job (sn, pjcb);
        job_recovered := TRUE;
      END /file_open/;
      gfp$get_segment_sfid (swap_ptr.cell_pointer, sfid, status);
      mmp$free_pages (swap_ptr.cell_pointer, 7fffffff(16), osc$wait, status);
      mmp$close_segment (swap_ptr, {validation_ring =} 3, status);
    END /file_attached/;

    recovered_job_count := recovered_job_count + 1;
    recovered_jobs^ [recovered_job_count].system_job_name := path [4];
    recovered_jobs^ [recovered_job_count].recovery_disposition_available := recovery_disposition_available;
    recovered_jobs^ [recovered_job_count].job_recovery_disposition := job_recovery_disposition;
    recovered_jobs^ [recovered_job_count].command_file_exists := FALSE;

    IF job_recovered THEN
{ The recovery disposition MUST be available and the job MUST have continued - if not, something is messy.

      IF NOT ((recovery_disposition_available) AND (job_recovery_disposition = jmc$continue_on_recovery)) THEN
        recovered_jobs^ [recovered_job_count].recovery_disposition_available := TRUE;
        recovered_jobs^ [recovered_job_count].job_recovery_disposition := jmc$continue_on_recovery;
      IFEND;

      recovered_jobs^ [recovered_job_count].local_file_name := uname;
      syp$increment_avt_r1 (sfid);
    ELSE
      amp$return (uname, status);

{ The swap file will be purged during queue recovery.

    IFEND;

  PROCEND process_swap_file;

?? TITLE := '  PROCEDURE display_and_log_status', EJECT ??

{ PURPOSE:
{    If an abnormal status arises during job recovery, calling this procedure
{    will display the status to the system and job logs and, if job history
{    is active, it will emit a statistic to the history log.

  PROCEDURE display_and_log_status
    (    status_to_log: ost$status;
         system_job_name: jmt$system_supplied_name);

    VAR
      ignore_status: ost$status,
      reason: ost$name,
      str: string (255),
      str_len: integer;

    osp$generate_log_message ($pmt$ascii_logset [pmc$system_log, pmc$job_log], status_to_log, ignore_status);

    STRINGREP (str, str_len, ' Job not recovered: ', system_job_name);
    pmp$log_ascii (str (1, str_len), $pmt$ascii_logset [pmc$system_log, pmc$job_log], pmc$msg_origin_system,
          ignore_status);

    IF jmv$job_history_active THEN
      reason := '';
      osp$get_status_condition_name (status_to_log.condition, reason, ignore_status);
      jmp$emit_job_history_statistics (jml$non_recovery_of_job, osc$null_name, system_job_name,
            jmc$blank_system_supplied_name, NIL, NIL, reason, jmc$blank_system_supplied_name, ignore_status);
    IFEND;
  PROCEND display_and_log_status;

  PROCEDURE display_status
    (    status: ost$status);

    VAR
      ost: ost$status,
      status_p: ^ost$status;

    IF (status.condition = ose$job_severely_damaged) OR (status.condition = ose$path_table_locked) THEN
      status_p := ^status;
      osp$log_unformatted_status (status_p, $pmt$ascii_logset [pmc$system_log, pmc$job_log],
            pmc$msg_origin_system, { critical_message } FALSE);
    ELSE
      osp$generate_log_message ($pmt$ascii_logset [pmc$system_log, pmc$job_log], status, ost);
    IFEND;

  PROCEND display_status;

  PROCEDURE display
    (    t: string ( * ));

    VAR
      ost: ost$status;

    pmp$log_ascii (t, $pmt$ascii_logset [pmc$system_log, pmc$job_log], pmc$msg_origin_system, ost);
  PROCEND display;

?? TITLE := '  PROCEDURE osp$recovery_swap_io_error', EJECT ??

  PROCEDURE [XDCL] osp$recovery_swap_io_error;

{ This procedure is called to find and terminate any job that could not swap in
{ to run recovery because of an io error.

    VAR
      bi: integer,
      bn: integer,
      ijl_ordinal: jmt$ijl_ordinal,
      ijle_p: ^jmt$initiated_job_list_entry,
      service_class: jmt$service_class_index,
      status: ost$status;

    IF NOT jmp$system_job () THEN
      osp$system_error (' malicious user access', NIL);
      RETURN;
    IFEND;

  /search_for_job/
    FOR bn := LOWERBOUND (jmv$ijl_p.block_p^) TO jmv$ijl_p.max_block_in_use DO
      IF jmv$ijl_p.block_p^ [bn].index_p <> NIL THEN

      /search_ijl_block/
        FOR bi := LOWERVALUE (jmt$ijl_block_index) TO UPPERVALUE (jmt$ijl_block_index) DO
          IF jmv$ijl_p.block_p^ [bn].index_p^ [bi].entry_status <> jmc$ies_entry_free THEN
            IF jmc$dsw_recovery_swap_io_error IN jmv$ijl_p.block_p^ [bn].index_p^ [bi].
                  delayed_swapin_work THEN
              ijl_ordinal.block_number := bn;
              ijl_ordinal.block_index := bi;

{ Purge its swap and command files and terminate the job.

              jmp$get_ijle_p (ijl_ordinal, ijle_p);
              purge_unrecovered_job (ijle_p^.system_supplied_name, status);
              osp$set_status_abnormal ('SY', sye$recovery_swap_io_error, ijle_p^.system_supplied_name,
                    status);
              display_status (status);
              syp$terminate_unrecovered_job (ijl_ordinal);
              IF jmv$ijl_p.block_p^ [bn].index_p = NIL THEN
                EXIT /search_ijl_block/;
              IFEND;
            IFEND;
          IFEND;
        FOREND /search_ijl_block/;

      IFEND;
    FOREND /search_for_job/;

  PROCEND osp$recovery_swap_io_error;

?? TITLE := '  PROCEDURE osp$scan_ijl_for_recovered_jobs' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] osp$scan_ijl_for_recovered_jobs;

{ This procedure is called to allow recoverable jobs to swap in or to get rid
{ of any jobs for which the job or service class of the job is not defined; it is
{ called after 'startup commands' have been executed so that site-defined classes
{ are initialized before any jobs are allowed to execute.

    VAR
      bi: integer,
      bn: integer,
      ijl_ordinal: jmt$ijl_ordinal,
      ijle_p: ^jmt$initiated_job_list_entry,
      job_class: jmt$job_class,
      service_class: jmt$service_class_index,
      status: ost$status;

    IF NOT jmp$system_job () THEN
      osp$system_error (' malicious user access', NIL);
      RETURN;
    IFEND;

  /search_for_job/
    FOR bn := LOWERBOUND (jmv$ijl_p.block_p^) TO jmv$ijl_p.max_block_in_use DO
      IF jmv$ijl_p.block_p^ [bn].index_p <> NIL THEN
        FOR bi := LOWERVALUE (jmt$ijl_block_index) TO UPPERVALUE (jmt$ijl_block_index) DO
          IF jmv$ijl_p.block_p^ [bn].index_p^ [bi].entry_status <> jmc$ies_entry_free THEN
            IF jmc$dsw_job_recovery IN jmv$ijl_p.block_p^ [bn].index_p^ [bi].delayed_swapin_work THEN
              ijl_ordinal.block_number := bn;
              ijl_ordinal.block_index := bi;
              job_class := jmv$ijl_p.block_p^ [bn].index_p^ [bi].job_scheduler_data.job_class;
              service_class := jmv$ijl_p.block_p^ [bn].index_p^ [bi].job_scheduler_data.service_class;
              IF (NOT jmv$job_class_table_p^ [job_class].defined) OR
                    (jmv$service_classes [service_class] = NIL) OR
                    (NOT jmv$service_classes [service_class]^.attributes.defined) THEN

{ The job or service class this job belongs to is no longer defined.
{ Purge its swap and command files and terminate it.

                jmp$get_ijle_p (ijl_ordinal, ijle_p);
                purge_unrecovered_job (ijle_p^.system_supplied_name, status);
                osp$set_status_abnormal ('SY', sye$recovery_class_not_defined, ijle_p^.system_supplied_name,
                      status);
                display_status (status);
                syp$terminate_unrecovered_job (ijl_ordinal);
              IFEND;
            IFEND;
          IFEND;
        FOREND;

      IFEND;
    FOREND /search_for_job/;

{ Make sure that the MAXIMUM ACTIVE JOBS entry in the service class table for all classes with jobs to be
{ recovered is greater than 0.  Also set the scheduler event to check if there are jobs to be swapped in.

    syp$check_maxaj_and_ready_sched;

  PROCEND osp$scan_ijl_for_recovered_jobs;
?? TITLE := '  PROCEDURE purge_unrecovered_job', EJECT ??

  PROCEDURE purge_unrecovered_job
    (    system_job_name: jmt$system_supplied_name;
     VAR status: ost$status);

    PROCEDURE condh
      (    condition: pmt$condition;
           cd: ^pmt$condition_information;
           sa: ^ost$stack_frame_save_area;
       VAR ignore: ost$status);

      osp$set_status_from_condition ('OS', condition, sa, status, ignore);
      IF NOT ignore.normal THEN
        status := ignore;
      IFEND;
      EXIT purge_unrecovered_job;
    PROCEND condh;

    VAR
      path: array [1 .. 4] of pft$name,
      cel: integer,
      ce: string (255),
      pf_cycle: [READ {,oss$job_paged_literal} ] pft$cycle_selector := [pfc$highest_cycle];

    status.normal := TRUE;
    IF NOT jmp$system_job () THEN
      osp$system_error (' malicious user access', NIL);
      RETURN;
    IFEND;

    osp$establish_condition_handler (^condh, FALSE);

    path [1] := jmc$system_family;
    path [2] := jmc$system_user;
    path [4] := system_job_name;
    path [3] := jmc$job_swap_catalog;
    pfp$purge (path, pf_cycle, osc$null_name, status);
    IF NOT status.normal THEN
      display_status (status);
    IFEND;
    path [3] := jmc$job_input_catalog;
    pfp$purge (path, pf_cycle, osc$null_name, status);
    IF NOT status.normal THEN
      display_status (status);
    IFEND;

    status.normal := TRUE;

  PROCEND purge_unrecovered_job;
?? TITLE := '  PROCEDURE syp$job_recovery_flag_handler', EJECT ??

  PROCEDURE [XDCL] syp$job_recovery_flag_handler
    (    flagid: ost$system_flag);

{ This procedure is called as the first thing during job recovery - after system core recovery
{ (e.g. the first thing in the job template).  It is called in all tasks of a job being recovered.

    VAR
      xcb: ^ost$execution_control_block,
      ignore,
      status: ost$status;


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

      VAR
        ignore: ost$status;

{ the purpose of this handler is to detect lost job recovery conditions

      status.normal := TRUE;

      IF NOT osv$job_recovery_required THEN
        pmp$continue_to_cause (pmc$execute_standard_procedure, ignore);
        RETURN;
      IFEND;

      IF recovery_termination THEN
        pmp$continue_to_cause (pmc$execute_standard_procedure, ignore);
        RETURN;
      IFEND;
      IF condition.selector = pmc$user_defined_condition THEN
        pmp$continue_to_cause (pmc$execute_standard_procedure, ignore);
        RETURN;
      ELSEIF condition.selector = jmc$job_resource_condition THEN
        pmp$continue_to_cause (pmc$execute_standard_procedure, ignore);
        RETURN;
      ELSEIF condition.selector = ifc$interactive_condition THEN
        pmp$continue_to_cause (pmc$execute_standard_procedure, ignore);
        RETURN;
      ELSEIF condition.selector = pmc$pit_condition THEN
        pmp$continue_to_cause (pmc$execute_standard_procedure, ignore);
        RETURN;
      IFEND;

      osp$set_status_from_condition ('OS', condition, sa, status, ignore);
      display_status (status);
      ofp$display_status_message ('Job recovery failed - job idled', ignore);
      syp$process_job_rcv_failure ('Job recovery condition in syp$job_recovery_flag_handler', status);
    PROCEND avoid;

    IF (syv$job_recovery_step <> syc$jrs_jt_step) AND (syv$job_recovery_step <> syc$jrs_test_jt_step) THEN
      osp$system_error ('illegal job recovery call', NIL);
    IFEND;
    osv$job_recovery_required := TRUE;
    pmp$find_executing_task_xcb (xcb);
    IF xcb = jmp$job_monitor_xcb () THEN
      osp$establish_condition_handler (^avoid, TRUE);

{I dont want to do this, but I will.  Execute job recovery immediately in
{any ring.  This must be changed when we allow recovery of file activity.

      osp$recover_job;

      pmp$cause_task_condition ('OSC$JOB_RECOVERY               ', NIL, FALSE, FALSE, FALSE, TRUE, status);
      IF osv$job_recovery_required THEN

{Some procedure did not do a continue to cause -
{We do not dare to continue this job

        ofp$display_status_message ('Job recovery failed - job idled', ignore);
        syp$process_job_rcv_failure ('Job recovery was ignored', status);
      IFEND;
      osp$disestablish_cond_handler;
    ELSE { tasks other than jmtr }
      osp$establish_condition_handler (^avoid, TRUE);

{I dont want to do this, but I will.  Execute job recovery immediately in
{any ring.  This must be changed when we allow recovery of file activity.

      osp$recover_job;

      pmp$cause_task_condition ('OSC$JOB_RECOVERY               ', NIL, FALSE, FALSE, FALSE, TRUE, status);
      IF osv$job_recovery_required THEN

{Some procedure did not do a continue to cause -
{We do not dare to continue this job

        ofp$display_status_message ('Job recovery failed - job idled', ignore);
        syp$process_job_rcv_failure ('Job recovery was ignored', status);
      IFEND;
      osp$disestablish_cond_handler;
    IFEND;
  PROCEND syp$job_recovery_flag_handler;
?? TITLE := '  PROCEDURE osp$recover_job', EJECT ??

  PROCEDURE [XDCL, #GATE] osp$recover_job;

{ This procedure is called by the condition mechanism whenever the job recovery
{ condition is continued across the ring 2 boundary.

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

      VAR
        ignore: ost$status;

{ the purpose of this handler is to support recursive job recovery
{ conditions.

      status.normal := TRUE;
      IF NOT osv$job_recovery_required THEN
        pmp$continue_to_cause (pmc$execute_standard_procedure, ignore);
        RETURN;
      IFEND;
      IF recovery_termination THEN
        pmp$continue_to_cause (pmc$execute_standard_procedure, ignore);
        RETURN;
      IFEND;
      IF condition.selector = pmc$user_defined_condition THEN
        IF condition.user_condition_name = 'OSC$JOB_RECOVERY' THEN
          pmp$log_ascii (' Job recovery re-entered', $pmt$ascii_logset [pmc$system_log, pmc$job_log],
                pmc$msg_origin_system, status);
          pmp$continue_to_cause (pmc$execute_standard_procedure, ignore);
          recursive_recovery := TRUE;
          EXIT osp$recover_job;
        ELSE
          pmp$continue_to_cause (pmc$execute_standard_procedure, ignore);
          RETURN;
        IFEND;
      ELSEIF condition.selector = pmc$block_exit_processing THEN
        IF recursive_recovery OR recovery_termination THEN

{ assume this was caused by the EXIT above, or by pmp$exit.

          RETURN;
        IFEND;
      ELSEIF condition.selector = jmc$job_resource_condition THEN
        pmp$continue_to_cause (pmc$execute_standard_procedure, ignore);
        RETURN;
      ELSEIF condition.selector = ifc$interactive_condition THEN
        pmp$continue_to_cause (pmc$execute_standard_procedure, ignore);
        RETURN;
      ELSEIF condition.selector = pmc$pit_condition THEN
        pmp$continue_to_cause (pmc$execute_standard_procedure, ignore);
        RETURN;
      IFEND;

      osp$set_status_from_condition ('OS', condition, sa, status, ignore);
      display_status (status);
      ofp$display_status_message ('Job recovery failed - job idled', ignore);
      syp$process_job_rcv_failure ('Job recovery condition in osp$recover_job', status);
    PROCEND ch;
?? EJECT ??

    VAR
      display_selections: oft$display_kinds,
      dummy_sdt: mmt$max_sdt_p,
      i: integer,
      ignore: ost$status,
      j: integer,
      job_mode: jmt$job_mode,
      null_dispatching_info: jmt$dispatching_control_info,
      old_jrs: syt$job_recovery_step,
      pi: ^integer,
      recursive_recovery: boolean,
      sdtx_p: mmt$max_sdtx_p,
      sdtxe_p: ^mmt$segment_descriptor_extended,
      status: ost$status,
      xcb: ^ost$execution_control_block;

    osp$verify_system_privilege;

    IF (syv$job_recovery_step <> syc$jrs_jt_step) AND (syv$job_recovery_step <> syc$jrs_test_jt_step) THEN
      osp$system_error ('illegal job recovery call', NIL);
    IFEND;
    recursive_recovery := FALSE;
    pmp$find_executing_task_xcb (xcb);
    osp$establish_condition_handler (^ch, TRUE);
    IF xcb = jmp$job_monitor_xcb () THEN
      IF osv$inhibit_job_recovery_count > 0 THEN
        job_recovery_inhibited := TRUE;
      IFEND;

{     Clear RHFAM job table entry pointer to prevent an RHFAM job from
{     attempting to access unrecovered tables in network paged.

      rfv$job_entry_pointer := NIL;

      WHILE syv$job_task_count <> 1 DO

{ jmtr - wait for all other tasks to synch

        pmp$delay (syv$job_recovery_wait_time, ignore);
      WHILEND;
      ofp$display_status_message ('Job recovery in progress', ignore);


{ put job template recovery stuff here

      jmp$record_job_attributes (^jmv$job_attributes, jmv$job_recovery_information_p, status);
      IF NOT status.normal THEN
        pmp$log_ascii (' Job template recovery failed', $pmt$ascii_logset [pmc$system_log, pmc$job_log],
              pmc$msg_origin_system, status);
        syp$process_job_rcv_failure (' jmp$record_job_attributes failed', status);
      IFEND;

      IF syc$tjr_recursive_recovery IN syv$test_jr_job THEN
        syp$clear_job_recovery_test (job, syc$tjr_recursive_recovery);
        WHILE TRUE DO
          pmp$wait (1000, 1000);
        WHILEND;
      IFEND;
      IF syc$tjr_fail_prior_jfr IN syv$test_jr_job THEN
        pi := NIL;
        pi^ := 0;
      IFEND;

      cmp$recover_subsystem_io_table (status);
      IF NOT status.normal THEN
        pmp$log_ascii (' Job template recovery failed', $pmt$ascii_logset [pmc$system_log, pmc$job_log],
              pmc$msg_origin_system, status);
        syp$process_job_rcv_failure (' cmp$recover_subsystem_io_table failed', status);
      IFEND;

      dfp$recover_jobs_servers (status);
      IF NOT status.normal THEN
        pmp$log_ascii (' Job recovery failed (job servers)', $pmt$ascii_logset [pmc$system_log, pmc$job_log],
              pmc$msg_origin_system, status);
        syp$process_job_rcv_failure (' dfp$recover_jobs_servers failed', status);
      IFEND;

      display_selections := $oft$display_kinds [ofc$dt_initiated_job_display, ofc$dt_unit_statistic_display];
      ofp$purge_incremental_data (display_selections, status);
      IF NOT status.normal THEN
        pmp$log_ascii (' Job recovery ofp$purge_incremental_data failed', $pmt$ascii_logset
              [pmc$system_log, pmc$job_log], pmc$msg_origin_system, status);
        {NOTE: We do not hang the job in this case, as it does not hurt to continue.
        status.normal := TRUE;
      IFEND;

      fmp$recover_job_files (status);
      IF status.normal AND job_recovery_inhibited THEN
        osp$set_status_abnormal ('SY', sye$task_inhibited_recovery, '', status);
        pmp$log_ascii (' Job recovery inhibited', $pmt$ascii_logset [pmc$system_log, pmc$job_log],
              pmc$msg_origin_system, ignore);
      IFEND;

      IF NOT status.normal THEN
        pmp$log_ascii (' Job recovery failed (job files)', $pmt$ascii_logset [pmc$system_log, pmc$job_log],
              pmc$msg_origin_system, ignore);
        IF syc$tjr_touch_unrec_segment IN syv$test_jr_job THEN
          mmp$get_max_sdt_sdtx_pointer (xcb, dummy_sdt, sdtx_p);
          FOR i := 0 TO xcb^.xp.segment_table_length DO
            sdtxe_p := ^sdtx_p^.sdtx_table [i];
            IF sdtxe_p^.sfid.residence = gfc$tr_system_wait_recovery THEN
              pi := #ADDRESS (3, i, 0);
              j := pi^;
            IFEND;
          FOREND;
        IFEND;
        IF (status.condition = pfe$not_all_pfs_recovered) OR (status.condition = fme$not_all_pfs_recovered) OR
              (status.condition = fme$tape_files_not_recovered) OR
              (status.condition = fme$not_all_files_recovered) OR
              (status.condition = fme$tape_resource_not_recovered) OR
              (status.condition = sye$task_inhibited_recovery) THEN
          pmp$log_ascii (' Recovering job being terminated (job files)', $pmt$ascii_logset
                [pmc$system_log, pmc$job_log], pmc$msg_origin_system, ignore);
          display_status (status);
          ofp$display_status_message ('Job recovery failed - job being terminated', ignore);

          nlp$recover_task_activity (ignore);
          IF NOT ignore.normal THEN
            job_recovery_inhibited := TRUE;
          IFEND;

          pmp$get_job_mode (job_mode, ignore);
          CASE job_mode OF
          = jmc$interactive_connected =
            IF jmv$job_attributes.originating_application_name = osc$timesharing THEN
              jmp$handle_ts_system_disconnect (ignore);
            ELSE
              iip$disconnect_job (iic$dont_end_connection, iic$dont_start_new_job, ignore);
              iip$terminate_disconnected_job;
            IFEND;
          = jmc$interactive_cmnd_disconnect, jmc$interactive_line_disconnect, jmc$interactive_sys_disconnect =
            IF jmv$job_attributes.originating_application_name <> osc$timesharing THEN
              iip$terminate_disconnected_job;
            IFEND;
          ELSE
          CASEND;

          syp$increment_file_rcv_failure;
          syp$log_recovery_failure (' Files not recovered - job terminated', status);

{ terminate the job - this is tricky
{ Will not return if syp$jt_recovery_complete fails.

          syp$jt_recovery_complete (ignore);

          recovery_termination := TRUE;
          pmp$exit (status);
        ELSE
          pmp$log_ascii (' Job termination not possible', $pmt$ascii_logset [pmc$system_log, pmc$job_log],
                pmc$msg_origin_system, ignore);
          display_status (status);
          ofp$display_status_message ('Job recovery failed - job idled', ignore);
          syp$process_job_rcv_failure ('fmp$recover_job_files failed', status);
        IFEND;
      IFEND;
      IF syc$tjr_fail_post_jfr IN syv$test_jr_job THEN
        pi := NIL;
        pi^ := 0;
      IFEND;

      IF syv$job_recovery_step <> syc$jrs_test_jt_step THEN
        mlp$recover_job_environment (status);
        IF NOT status.normal THEN
          pmp$log_ascii (' Job recovery failed (job environment)', $pmt$ascii_logset
                [pmc$system_log, pmc$job_log], pmc$msg_origin_system, ignore);
          display_status (status);
          IF status.condition = ose$mem_link_not_available THEN
            job_recovery_inhibited := TRUE;
          ELSE
            ofp$display_status_message ('Job recovery failed - job idled', ignore);
            syp$process_job_rcv_failure ('mli recovery failed', status);
          IFEND;
        IFEND;

        nlp$recover_task_activity (ignore);
        IF NOT ignore.normal THEN
          job_recovery_inhibited := TRUE;
        IFEND;

        pmp$get_job_mode (job_mode, status);
        CASE job_mode OF
        = jmc$interactive_cmnd_disconnect, jmc$interactive_line_disconnect, jmc$interactive_sys_disconnect,
              jmc$interactive_connected =
          IF jmv$job_attributes.originating_application_name = osc$timesharing THEN
            jmp$handle_ts_system_disconnect (status);
          ELSE
            iip$disconnect_job (iic$dont_end_connection, iic$dont_start_new_job, status);
          IFEND;
        ELSE
        CASEND;

      IFEND;

{ Will not return if syp$jt_recovery_complete fails.

      syp$jt_recovery_complete (status);

      IF job_recovery_inhibited THEN
        IF (NOT status.normal) AND (status.condition <> ose$mem_link_not_available) THEN
          osp$set_status_abnormal ('SY', sye$task_inhibited_recovery, '', status);
        IFEND;
        recovery_termination := TRUE;
        pmp$exit (status);
      IFEND;

      ofp$display_status_message ('Job recovery complete', ignore);

{ Reset dispatching priority

      null_dispatching_info.dispatching_priority := jmc$null_dispatching_priority;
      jmp$change_dispatching_prior_r1 (tmc$cpo_recovery, jmv$jcb.ijl_ordinal, jmv$jcb.system_name,
            null_dispatching_info, status);

{ wait for all jobs to complete recovery

      osv$job_recovery_required := FALSE;
      osv$job_recovery_alert := TRUE;

      WHILE syv$recovering_job_count <> 0 DO
        pmp$wait (30000, 30000);
      WHILEND;
    ELSE
      old_jrs := syv$job_recovery_step;
      IF osv$inhibit_job_recovery_count > 0 THEN
        job_recovery_inhibited := TRUE;
      IFEND;
      syp$decrement_job_task_count;
      WHILE syv$job_recovery_step <> syc$jrs_recovery_complete DO

{ non jmtr tasks - wait for jmtr to complete job recovery

        pmp$delay (syv$job_recovery_wait_time, ignore);
      WHILEND;
      IF old_jrs <> syc$jrs_test_jt_step THEN
        mlp$recover_job_environment (status);
        IF NOT status.normal THEN
          IF status.condition = ose$mem_link_not_available THEN
            job_recovery_inhibited := TRUE;
          ELSE
            osp$system_error (' job recovery mli rec', ^status);
          IFEND;
        IFEND;
      IFEND;

      IF NOT job_recovery_inhibited THEN
        nlp$recover_task_activity (ignore);
        IF NOT ignore.normal THEN
          job_recovery_inhibited := TRUE;
        IFEND;
      IFEND;
      rfp$recover_task_activity (ignore);

      IF job_recovery_inhibited THEN
        IF (NOT status.normal) AND (status.condition <> ose$mem_link_not_available) THEN
          osp$set_status_abnormal ('SY', sye$task_inhibited_recovery, '', status);
        IFEND;
        recovery_termination := TRUE;
        pmp$exit (status);
      IFEND;

      osv$job_recovery_required := FALSE;
      osv$job_recovery_alert := TRUE;

      WHILE syv$recovering_job_count <> 0 DO
        pmp$wait (30000, 30000);
      WHILEND;
    IFEND;
    osp$disestablish_cond_handler;
  PROCEND osp$recover_job;
?? TITLE := '  PROCEDURE osp$set_job_recovery_test', EJECT ??

  PROCEDURE [XDCL, #GATE] osp$set_job_recovery_test
    (    parameter_list: clt$parameter_list;
     VAR status: ost$status);

{  PDT setjrt_pdt (environment,e: key job, system, clear_job, clear_system = job
{      option: integer 0 .. 255 = $required)

?? PUSH (LISTEXT := ON) ??

    VAR
      setjrt_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table :=
            [^setjrt_pdt_names, ^setjrt_pdt_params];

    VAR
      setjrt_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 3] of
            clt$parameter_name_descriptor := [['ENVIRONMENT', 1], ['E', 1], ['OPTION', 2]];

    VAR
      setjrt_pdt_params: [STATIC, READ, cls$pdt_parameters] array [1 .. 2] of clt$parameter_descriptor := [

{ ENVIRONMENT E

      [[clc$optional_with_default, ^setjrt_pdt_dv1], 1, 1, 1, 1, clc$value_range_not_allowed,
            [^setjrt_pdt_kv1, clc$keyword_value]],

{ OPTION

      [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$integer_value, 0, 255]]];

    VAR
      setjrt_pdt_kv1: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 4] of ost$name := ['JOB',
            'SYSTEM', 'CLEAR_JOB', 'CLEAR_SYSTEM'];

    VAR
      setjrt_pdt_dv1: [STATIC, READ, cls$pdt_names_and_defaults] string (3) := 'job';

?? POP ??

    VAR
      clear: boolean,
      t: (job, system),
      value: clt$value;

    clp$scan_parameter_list (parameter_list, setjrt_pdt, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    clp$get_value ('ENVIRONMENT', 1, 1, clc$low, value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    IF value.name.value = 'JOB' THEN
      t := job;
      clear := FALSE;
    ELSEIF value.name.value = 'CLEAR_JOB' THEN
      t := job;
      clear := TRUE;
    ELSEIF value.name.value = 'CLEAR_SYSTEM' THEN
      t := system;
      clear := TRUE;
    ELSE
      t := system;
      clear := FALSE;
    IFEND;

    clp$get_value ('OPTION', 1, 1, clc$low, value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF clear THEN
      syp$clear_job_recovery_test (t, value.int.value);
    ELSE
      syp$set_job_recovery_test (t, value.int.value);
    IFEND;

  PROCEND osp$set_job_recovery_test;
?? OLDTITLE, OLDTITLE ??
MODEND sym$job_recovery_r3;

