?? RIGHT := 110 ??
?? TITLE := 'NOS/VE Job Recovery Ring 1 Procedures' ??
MODULE sym$job_recovery_r1;
?? RIGHT := 110 ??

{
{              job recovery functioning
{              system job - continuation deadstart
{              -----------------------------------
{
{     osm$job_template_initialization
{         osp$recover_executing_jobs
{              syp$init_job_rec_from_image (ready system to recover jobs from
{                                            image file)
{              pfp$validate_catalog (swap catalog)
{              syp$begin_job_recovery
{              for every swap file (job)
{                   pfp$restricted_attach (swap file)
{                   bap$open
{                   syp$job_recovery_from_image (manually swap out jobs from
{                                                  memory image to swap file)
{                   jmp$rebuild_executing_job (rebuild KJL)
{                   syp$recover_job_r1 (rebuild ijl, ptl for swapin)
{              forend
{              syp$end_job_recovery
{         osp$complete_job_recovery
{              process delayed purges from osp$recover_executing_jobs
{              start volume space recovery task
{              syp$complete_job_recovery (notify scheduler of recovered jobs)
{
{
{                        within recovering jobs (tasks)
{                        -------------------------------
{
{                                  both tasks
{    jmtr task                                                   other tasks
{    -----------------------------------------------------------------------
{                                  syp$mfh_for_job_recovery (monitor flag)
{    dmp$recover_job_temp_file_space                             wait for jmtr
{                                                                     task
{                                  flag yourself
{                                  osp$recover_job (system flag)
{                                  cause_task_condition
{                                  rollback of ring 2 code
{    wait for all tasks to reach jt
{    syp$decrement_job_task_count
{                                                                wait for
{                                                      syp$jt_recovery_complete
{    fmp$recover_job_files
{    mli recovery
{    disconnect if interactive
{    syp$jt_recovery_complete
{                                                                mli recovery
{                                  wait for all jobs to finish job recovery
{                                  resume user code
{                                  On first access to server
{                                    in the job after server active.
{                                    dfp$recovery_job

?? PUSH (LISTEXT := ON) ??
*copyc dpt$window_id
*copyc dpp$put_critical_message
*copyc dpp$put_next_line
*copyc dst$image_status
*copyc fmc$test_jr_constants
*copyc jmc$job_management_id
*copyc jmc$special_dispatch_priorities
*copyc jmc$null_ajl_ordinal
*copyc jme$queued_file_conditions
*copyc jmt$destination_usage
*copyc jmt$job_class
*copyc jmt$job_recovery_disposition
*copyc jmt$service_class_index
*copyc jmt$system_supplied_name
*copyc jst$swap_file_descriptor
*copyc mmd$segment_access_condition
*copyc mmt$ast_index
*copyc mmt$io_control_block
*copyc mmt$iocb_index
*copyc mmt$rb_change_segment_table
*copyc mmt$segment_access_state
*copyc ose$job_recovery_exceptions
*copyc oss$job_fixed
*copyc ost$heap
*copyc ost$name
*copyc syc$job_recovery_enabled
*copyc syc$monitor_request_codes
*copyc sye$job_recovery_conditions
*copyc syt$job_recovery_step
*copyc syt$failure_reason_list
*copyc syt$rb_job_recovery
*copyc syt$system_core_condition
*copyc syt$user_defined_condition
*copyc tmc$wait_times
?? POP ??
?? NEWTITLE := '  Global Procedure Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc dmp$allocate_file_space_r1
*copyc dfv$recover_active_families
*copyc dmp$fetch_eoi
*copyc dmp$increment_class_activity
*copyc dmp$recover_job_temp_file_space
*copyc dmp$return_temp_file_space
*copyc dmp$set_eoi
*copyc dmp$verify_job_volumes
*copyc dsp$get_data_from_rdf
*copyc dsp$get_nve_image_description
*copyc dsp$store_data_in_rdf
*copyc gfp$get_fde_p
*copyc gfp$get_fde_p_from_image
*copyc gfp$get_locked_fde_p
*copyc gfp$get_segment_sfid
*copyc gfp$unlock_fde_p
*copyc i#build_adaptable_array_ptr
*copyc i#call_monitor
*copyc i#disable_traps
*copyc i#enable_traps
*copyc i#move
*copyc i#restore_traps
*copyc jmp$allocate_more_ijl_space
*copyc jmp$cleanup_unrecovered_job
*copyc jmp$delete_ijl_entry
*copyc jmp$get_ijle_p
*copyc jmp$job_monitor_xcb
*copyc jmp$notify_queued_files_job_end
*copyc lgp$add_entry_to_system_log
*copyc mmp$assign_contiguous_memory
*copyc mmp$build_segment
*copyc mmp$free_pages
*copyc mmp$get_sdt_entry_p
*copyc mmp$get_sdtx_entry_p
*copyc mmp$get_max_sdt_sdtx_pointer
*copyc mmp$invalidate_segment
*copyc mmp$issue_ring1_segment_request
*copyc mmp$write_modified_pages
*copyc ocp$find_debug_address
*copyc ofp$job_begin
*copyc osp$append_status_integer
*copyc osp$begin_subsystem_activity
*copyc osp$clear_signature_lock
*copyc osp$check_for_job_recovery
*copyc osp$decrement_locked_variable
*copyc osp$end_subsystem_activity
*copyc osp$expand_ptl
*copyc osp$fatal_system_error
*copyc osp$increment_locked_variable
*copyc osp$initialize_signature_lock
*copyc osp$set_signature_lock
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc osp$system_error
*copyc pmp$delay
*copyc pmp$find_executing_task_xcb
*copyc pmp$get_executing_task_gtid
*copyc pmp$set_system_flag
*copyc pmp$zero_out_table
*copyc syp$set_status_from_mtr_status
*copyc syp$wait
*copyc tmp$get_monitor_fault
*copyc tmp$ready_system_task1
*copyc syp$invoke_system_debugger
*copyc syp$establish_condition_handler
?? POP ??
?? OLDTITLE ??
?? NEWTITLE := '  Global Variable Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc dfv$job_recovery_enabled
*copyc dmv$ds_msg_update_interval
*copyc dmv$display_recovery_messages
*copyc gfv$null_sfid
*copyc jmv$ajl_p
*copyc jmv$ijl_p
*copyc jmv$jcb
*copyc jmv$job_counts
*copyc jmv$jmtr_xcb
*copyc jmv$job_scheduler_event
*copyc jmv$job_sched_events_selected
*copyc jmv$kjl_p
*copyc jmv$max_service_class_in_use
*copyc jmv$null_ijl_ordinal
*copyc jmv$refresh_job_candidates
*copyc jmv$service_classes
*copyc jmv$system_core_id
*copyc jmv$system_ijl_ordinal
*copyc jmv$task_private_templ_p
*copyc mmv$default_sdtx_entry
*copyc mmv$pft_p
*copyc mmv$gpql
*copyc mtv$executing_ajl_at_failure
*copyc mtv$halt_cpu_ring_number
*copyc mtv$processor_mode
*copyc osv$job_fixed_heap
*copyc osv$mainframe_pageable_heap
*copyc osv$mainframe_wired_heap
*copyc osv$page_size
*copyc pmv$task_template
*copyc syv$detailed_critical_displays
*copyc syv$test_jr_system
*copyc syv$nosve_job_template
*copyc syv$recovering_job_count
*copyc tmv$null_global_task_id
*copyc tmv$ptl_p
?? POP ??
?? OLDTITLE ??
?? NEWTITLE := '  Global Variable Declarations Declared by This Module', EJECT ??

  TYPE
    jxcbl = record
      head: ^ost$execution_control_block,
      lock: ost$signature_lock,
    recend;


  VAR
    job_xcb_list: [XREF, oss$job_fixed] record
      head: ^ost$execution_control_block,
      lock: ost$signature_lock,
    recend,
    syv$allow_jr_test: [XREF] boolean;

  VAR
    decrement_required: [STATIC, oss$job_fixed] boolean := FALSE,
    image_offset: [STATIC] ost$segment_offset,
    image_segment_number: [STATIC] ost$segment,
    inhibit_job_recovery: [oss$job_fixed] integer := 0,
    job_task_count_lock: [oss$job_fixed] ost$signature_lock := [0],
    last_inhibit_job_recovery_p: [oss$job_fixed] ^cell := NIL,
    mtv$saved_halt_cpu_ring_number: [XDCL] 0 .. 0ff(16) := 0,
    oajlp: [STATIC] ^jmt$active_job_list,
    oihtp: [STATIC] ^mmt$old_modified_bits,
    opftp: [STATIC] ^mmt$page_frame_table,
    opqlp: [STATIC] ^mmt$global_page_queue_list,
    optlp: [STATIC] ^tmt$primary_task_list,
    recovering_job_count_lock: ost$signature_lock := [0],
    recovery_failure_lock: ost$signature_lock := [0],
    recovery_load_offset: [STATIC] ost$segment_offset,
    rmfwsn: [STATIC] 0 .. 0fff(16),
    syv$attached_server_file_count: [XDCL, #GATE, oss$job_fixed] integer := 0,
    syv$debug_job_recovery: [XDCL, #GATE] boolean := FALSE,
    syv$discarded_page_count: [XDCL] integer := 0,
    syv$failure_reason_p: [XDCL, #GATE] ^syt$failure_reason_list := NIL,
    syv$file_rcv_failure_count: [XDCL, #GATE] integer := 0,
    syv$job_recovery_option: [XDCL, #GATE] integer := syc$jre_enabled,
    syv$job_recovery_step: [XDCL, #GATE, oss$job_fixed] syt$job_recovery_step := syc$jrs_initial_step,
    syv$job_recovery_wait_time: [XDCL, #GATE, oss$job_fixed] integer := 500,
    syv$job_task_count: [XDCL, #GATE, oss$job_fixed] integer := 0,
    syv$recovery_failure_count: [XDCL, #GATE] integer := 0,
    syv$system_is_idling: [STATIC, oss$mainframe_pageable] boolean := FALSE,
    syv$system_was_idle: boolean := FALSE,
    syv$test_jr_job: [XDCL, #GATE, oss$job_fixed] syt$test_jr_set := $syt$test_jr_set [],
    oijlp: [STATIC] jmt$ijl_p := [NIL, * , * ],
    wid: dpt$window_id;

{Debug code

  VAR
    syv$detach_nil_rsv_cycle_count: [XDCL, #GATE, oss$mainframe_pageable] integer := 0,
    syv$detach_purged_rsv_cyc_count: [XDCL, #GATE, oss$mainframe_pageable] integer := 0,
    syv$reattach_purged_rsv_cyc_cnt: [XDCL, #GATE, oss$mainframe_pageable] integer := 0;

{End Debug code

  PROCEDURE log
    (    text: string ( * ));

    VAR
      log_time: ost$time,
      ost,
      status: ost$status;

    lgp$add_entry_to_system_log (pmc$msg_origin_system, text, log_time, status);
    IF NOT status.normal THEN
      syp$invoke_system_debugger ('   ', 0, ost);
    IFEND;
  PROCEND log;

*if false
*copyc syp$display_deadstart_message

  PROCEDURE snap
    (    object: string ( * <= 31);
         address: ^cell;
         size: integer);

    VAR
      msg: string (80),
      i: integer;

    STRINGREP (msg, i, ' ', object, ' Address: ', address, ' Size: ', size);
    syp$display_deadstart_message (msg (1, i));

  PROCEND snap;
*ifend
?? TITLE := 'PROCEDURE [XDCL] syp$order_job_fixed_pages', EJECT ??

  PROCEDURE [XDCL] syp$order_job_fixed_pages
    (    job_page_count: mmt$page_frame_index;
         sfdp: ^jst$swap_file_descriptor;
         job_fixed_offset_list: ^array [0 .. * ] of integer;
     VAR job_fixed: ^array [0 .. 7fffffff(16)] of cell;
     VAR job_fixed_segn: ost$segment;
     VAR status: ost$status);

    VAR
      attributes: mmt$segment_attrib_descriptor,
      job_fixed_p: ^cell,
      job_fixed_segment_p: mmt$segment_pointer,
      max_seg_len: ost$segment_length,
      page_index: mmt$page_frame_index,
      page_number: mmt$page_frame_index,
      swap_file_segn: ost$segment;

    status.normal := TRUE;


    attributes.validating_ring_number := 1;
    attributes.file_limits_to_enforce := sfc$no_limit;
    attributes.pointer_kind := mmc$cell_pointer;
    attributes.user_attributes := NIL;
    attributes.sfid := gfv$null_sfid;
    mmp$build_segment (attributes, NIL, job_fixed_segment_p, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    job_fixed_segn := #SEGMENT (job_fixed_segment_p.cell_pointer);
    job_fixed := #ADDRESS (1, job_fixed_segn, 0);
    swap_file_segn := #SEGMENT (sfdp);

{ Copy job fixed from the swap file to a segment so that we have a sequence of bytes
{ that is in pva order.  The swap file is not necessarily in pva order.  Keep an array
{ of page numbers that describe the job fixed order in the swap file.
{ Pages of fixed segments that are not JOB FIXED cannot be counted.
{ Assumption: The ASID for the job_fixed segment is correct in the swap_file_descriptor.
{ Note: The second clause of the IF statement below indicates that we are looking for pages in the job_fixed
{ segment which are contiguous but are not really job_fixed pages.

    FOR page_index := 0 TO job_page_count - 1 DO
      IF (sfdp^.swapped_page_descriptors [page_index].pft_entry.queue_id = mmc$pq_job_fixed) AND
            (sfdp^.swapped_page_descriptors [page_index].pft_entry.sva.asid = sfdp^.ijl_entry.job_fixed_asid)
            THEN
        page_number := sfdp^.swapped_page_descriptors [page_index].pft_entry.sva.offset DIV osv$page_size;
        job_fixed_p := #ADDRESS (1, swap_file_segn, page_index * osv$page_size);
        i#move (job_fixed_p, #LOC (job_fixed^ [page_number * osv$page_size]), osv$page_size);
        job_fixed_offset_list^ [page_number] := page_index;
      IFEND;
    FOREND;

  PROCEND syp$order_job_fixed_pages;

?? TITLE := 'PROCEDURE [XDCL] syp$update_flags', EJECT ??

{ This procedure is currently only called by job recovery and when the system
{ is idling.  It assumes the PTL is not changing under us.

  PROCEDURE [XDCL] syp$update_flags
    (    xcb_p: ^ost$execution_control_block;
         ptlp: ^tmt$primary_task_list;
     VAR flags_updated: boolean);

    VAR
      ptle_p: ^tmt$primary_task_list_entry,
      ptlo: ost$task_index;

    flags_updated := FALSE;
    ptlo := xcb_p^.global_task_id.index;
    ptle_p := ^ptlp^ [ptlo];
    IF (ptle_p^.monitor_flags <> $syt$monitor_flags []) OR (ptle_p^.system_flags <> $tmt$system_flags []) THEN

{ Update the job fixed array copy of the XCB.  The caller of this routine will
{ copy the updated job fixed array to the swap file segment before writing out
{ all the job fixed pages.

      xcb_p^.monitor_flags := xcb_p^.monitor_flags + ptle_p^.monitor_flags;
      xcb_p^.monitor_flags := xcb_p^.monitor_flags - $syt$monitor_flags [mmc$mf_volume_unavailable];
      xcb_p^.system_flags := xcb_p^.system_flags + ptle_p^.system_flags;
      xcb_p^.system_flags := xcb_p^.system_flags - $tmt$system_flags [mmc$volume_unavailable_flag];
      xcb_p^.xp.user_condition_register := xcb_p^.xp.user_condition_register +
            $ost$user_conditions [osc$free_flag];
      xcb_p^.wait_inhibited := TRUE;

      ptle_p^.monitor_flags := $syt$monitor_flags [];
      ptle_p^.system_flags := $tmt$system_flags [];
      flags_updated := TRUE;
    IFEND;

  PROCEND syp$update_flags;

?? TITLE := 'PROCEDURE [XDCL] syp$write_job_fixed_pages', EJECT ??

{ Callers of this routine must call mmp$free_pages to free the pages in
{ memory belonging to the swap file when done accessing them.

  PROCEDURE [XDCL] syp$write_job_fixed_pages
    (    job_fixed_page_count: mmt$page_frame_index;
         job_fixed: ^array [0 .. 7fffffff(16)] of cell;
         sfdp: ^jst$swap_file_descriptor;
     VAR status: ost$status);

    VAR
      job_fixed_p: ^cell,
      page_index: mmt$page_frame_index,
      page_number: mmt$page_frame_index,
      swap_file_segn: ost$segment;

    status.normal := TRUE;
    swap_file_segn := #SEGMENT (sfdp);

{ Copy the job fixed array back into the swap file.
{ Pages of job fixed that are not JOB FIXED cannot be counted.
{ Assumption: The ASID for the job_fixed segment is correct in the swap_file_descriptor.
{ Note: The second clause of the IF statement below indicates that we are looking for pages in the job_fixed
{ segment which are contiguous but are not really job_fixed pages.

    FOR page_index := 0 TO job_fixed_page_count - 1 DO
      IF (sfdp^.swapped_page_descriptors [page_index].pft_entry.queue_id = mmc$pq_job_fixed) AND
            (sfdp^.swapped_page_descriptors [page_index].pft_entry.sva.asid = sfdp^.ijl_entry.job_fixed_asid)
            THEN
        page_number := sfdp^.swapped_page_descriptors [page_index].pft_entry.sva.offset DIV osv$page_size;
        job_fixed_p := #ADDRESS (1, swap_file_segn, page_index * osv$page_size);
        i#move (#LOC (job_fixed^ [page_number * osv$page_size]), job_fixed_p, osv$page_size);
      IFEND;
    FOREND;

{ Write the job fixed pages of the swap file out to disk.

    mmp$write_modified_pages (#ADDRESS (1, swap_file_segn, 0), job_fixed_page_count * osv$page_size, osc$wait,
          status);

  PROCEND syp$write_job_fixed_pages;
?? TITLE := 'PROCEDURE syp$recover_job_r1', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$recover_job_r1
    (    swap_file: ^cell;
         jcb: ^jmt$job_control_block;
         oijlep: ^jmt$initiated_job_list_entry;
     VAR recovery_disposition_available: boolean;
     VAR job_recovery_disposition: jmt$job_recovery_disposition;
     VAR status: ost$status);

    PROCEDURE display_address
      (    pva: ^cell);

      VAR
        display_string: string (255),
        found: boolean,
        module_name: pmt$program_name,
        procedure_name: pmt$program_name,
        section_offset: ost$segment_offset,
        status: ost$status,
        string_length: integer;

      ocp$find_debug_address (#SEGMENT (pva), #OFFSET (pva), found, module_name, procedure_name,
            section_offset, status);
      IF NOT status.normal OR NOT found THEN
        module_name := ' ';
        procedure_name := ' ';
        section_offset := 0;
      IFEND;


      STRINGREP (display_string, string_length, pva, ' ', module_name, ' ', procedure_name, ' ',
            section_offset);
      log (display_string (1, string_length));

    PROCEND display_address;

    PROCEDURE display_xcb;

      PROCEDURE scch
        (    mf: ost$monitor_fault;
             ctc: ^ost$minimum_save_area;
         VAR continue: syt$continue_option);

        EXIT display_xcb; {----->
      PROCEND scch;

      VAR
        pjxcbl: ^jxcbl,
        xcb: ^ost$execution_control_block,
        ring,
        segment,
        offset,
        strl,
        x0,
        xcbo: integer,
        so: ost$segment_offset,
        modname,
        procname: pmt$program_name,
        found: boolean,
        status: ost$status,
        str: string (255);

      syp$establish_condition_handler (^scch);
      pjxcbl := ^job_fixed^ [#OFFSET (^job_xcb_list)];
      xcb := pjxcbl^.head;
      log ('Recovery aborted -  xcb info:');

    /follow_xcb_chain/
      WHILE xcb <> NIL DO
        xcbo := #OFFSET (xcb);
        xcb := ^job_fixed^ [#OFFSET (xcb)];
        ring := xcb^.xp.p_register.pva.ring;
        segment := xcb^.xp.p_register.pva.seg;
        offset := xcb^.xp.p_register.pva.offset;
        x0 := xcb^.xp.x_registers [0];

        ocp$find_debug_address (segment, offset, found, modname, procname, so, status);
        IF NOT found THEN
          modname := '  ';
          procname := '  ';
          so := 0;
        IFEND;

{ IF procname = 'I#CALL_MONITOR' THEN
{   segment := #segment (xcb^.xp.af);
{   offset := #offset (xcb^.xp.af);
{   ocp$find_debug_address (segment, offset, found, modname, procname, so,
{         status);
{ IFEND;

        STRINGREP (str, strl, xcb^.save9, ' ', ring: 2: #(16), segment: 4: #(16), offset: 9: #(16),
              ' ', modname, ' ', procname, so, ' x0', x0: 18: #(16));
        log (str (1, strl));

        xcb := xcb^.link;
      WHILEND /follow_xcb_chain/;

    PROCEND display_xcb;


    VAR
      display_string: string (70),
      string_length: integer,
      attached_server_file_count_p: ^integer,
      flags_updated: boolean,
      highest_page_number: mmt$page_frame_index,
      last_inhibit_job_recovery_p_p: ^^cell,
      ijl_ord: jmt$ijl_ordinal,
      ijlep: ^jmt$initiated_job_list_entry,
      ijr_p: ^integer,
      j: integer,
      jf_segnumber: ost$segment,
      jip_p: ^jmt$job_control_block,
      job_fixed: ^array [0 .. 7fffffff(16)] of cell,
      job_fixed_offset_list: ^array [0 .. * ] of integer,
      jr_req: syt$rb_job_recovery,
      jrs_p: ^syt$job_recovery_step,
      msg_status: ost$status,
      old_ijlep: ^jmt$initiated_job_list_entry,
      ost: ost$status,
      p_nosve_job_template: ^boolean,
      page_index: mmt$page_frame_index,
      page_number: mmt$page_frame_index,
      pc: mmt$page_frame_index,
      pjxcbl: ^jxcbl,
      pn: mmt$page_frame_index,
      po: ost$segment_offset,
      pqidi: mmt$page_frame_queue_id,
      queue_id: mmt$job_page_queue_index,
      sfdp: ^jst$swap_file_descriptor,
      swap_file_eoi: amt$file_byte_address,
      swap_file_offset: integer,
      swap_file_segn: 0 .. 0fff(16),
      swap_file_sfid: gft$system_file_identifier,
      task_index: ost$task_index,
      trick: ^packed record
        ring: 0 .. 0f(16),
        segment: 0 .. 0fff(16),
        offset: 0 .. 0ffffffff(16),
      recend,
      unrecoverable_file: boolean,
      volume_missing: boolean,
      write_job_fixed: boolean,
      xcb: ^ost$execution_control_block,
      xcbo: ost$segment_offset;

    PROCEDURE scch
      (    mf: ost$monitor_fault;
           ctc: ^ost$minimum_save_area;
       VAR continue: syt$continue_option);

      IF jr_req.task_list_p <> NIL THEN
        FREE jr_req.task_list_p IN osv$mainframe_wired_heap^;
      IFEND;

      IF ijlep <> NIL THEN
        jmp$delete_ijl_entry (ijl_ord);
      IFEND;

      osp$set_status_condition (sye$condition_encountered, status);
      EXIT syp$recover_job_r1; {----->
    PROCEND scch;

    ijlep := NIL;
    #SPOIL (ijlep);
    jr_req.task_list_p := NIL;
    syp$establish_condition_handler (^scch);
    swap_file_segn := #SEGMENT (swap_file);
    pc := 0;
    FOR queue_id := LOWERVALUE (mmt$job_page_queue_index) TO UPPERVALUE (mmt$job_page_queue_index) DO
      pc := pc + jcb^.swapped_job_entry.job_page_queue_count [queue_id];
    FOREND;
    IF (pc = 0) OR (jcb^.swapped_job_entry.swap_file_descriptor_page_count = 0) THEN
      osp$set_status_condition (sye$job_page_count_zero, status);
      RETURN; {----->
    IFEND;

{ ** WARNING
{    THE FOLLOWING LINE IS DEPENDANT ON PAGE SIZE

    i#build_adaptable_array_ptr (1, swap_file_segn, pc * osv$page_size,
          #SIZE (jst$swapped_page_descriptor) * (jcb^.swapped_job_entry.swap_file_descriptor_page_count + pc),
          0, #SIZE (jst$swapped_page_descriptor), #LOC (sfdp));

    IF sfdp^.ijl_entry.system_supplied_name <> jcb^.system_name THEN
      osp$set_status_condition (sye$bad_swap_file_descriptor, status);
      RETURN; {----->
    IFEND;

    ijl_ord := jcb^.ijl_ordinal;
    IF ijl_ord.block_number > UPPERBOUND (jmv$ijl_p.block_p^) THEN
      osp$set_status_condition (sye$bad_ijl_entry, status);
      RETURN; {----->
    IFEND;
    IF ijl_ord.block_index > UPPERVALUE (jmt$ijl_block_index) THEN
      osp$set_status_condition (sye$bad_ijl_entry, status);
      RETURN; {----->
    IFEND;

    IF NOT syv$system_was_idle THEN

{ If necessary, update the ijl entry in the swap file with the ijl entry from the image.
{ If the job was already swapped to disk when the system went down, no processing was done
{ to the job in syp$job_recovery_from_image.  If the job was not swapped to disk, then
{ syp$job_reocvery_from_image has already "swapped out" the job and updated the swap file
{ descriptor.
{ NOTE:  This code is dependent upon NOTHING changing the image ijl entry (oijlep).

      IF oijlep^.swap_status >= jmc$iss_swapout_io_complete THEN
        IF sfdp^.ijl_entry.system_supplied_name = oijlep^.system_supplied_name THEN
          sfdp^.ijl_entry := oijlep^;
          mmp$write_modified_pages (^sfdp^.ijl_entry, #SIZE (jmt$initiated_job_list_entry), osc$wait, status);
        IFEND;
      IFEND;
    IFEND;


{ There may be gaps in the job fixed pages.  Find the largest page number.
{ Assumption: The ASID for the job_fixed segment is correct in the swap_file_descriptor.
{ Note: The second clause of the IF statement below indicates that we are looking for pages in the job_fixed
{ segment which are contiguous but are not really job_fixed pages.

    pc := jcb^.swapped_job_entry.job_page_queue_count [mmc$pq_job_fixed];
    highest_page_number := 0;
    FOR page_index := 0 TO pc - 1 DO
      IF (sfdp^.swapped_page_descriptors [page_index].pft_entry.queue_id = mmc$pq_job_fixed) AND
            (sfdp^.swapped_page_descriptors [page_index].pft_entry.sva.asid = sfdp^.ijl_entry.job_fixed_asid)
            THEN
        page_number := sfdp^.swapped_page_descriptors [page_index].pft_entry.sva.offset DIV osv$page_size;
        IF page_number > highest_page_number THEN
          highest_page_number := page_number;
        IFEND;
      IFEND;
    FOREND;

    PUSH job_fixed_offset_list: [0 .. highest_page_number];
    jf_segnumber := 0;
    syp$order_job_fixed_pages (pc, sfdp, job_fixed_offset_list, job_fixed, jf_segnumber, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

  /jf_seg_open/
    BEGIN
      old_ijlep := ^sfdp^.ijl_entry;

      recovery_disposition_available := TRUE;
      job_recovery_disposition := old_ijlep^.queue_file_information.job_recovery_disposition;
      IF job_recovery_disposition = jmc$terminate_on_recovery THEN
        osp$set_status_abnormal (jmc$job_management_id, jme$job_recovery_or_abort_set, 'TERMINATED', status);
        EXIT /jf_seg_open/; {----->
      ELSEIF job_recovery_disposition = jmc$restart_on_recovery THEN
        osp$set_status_abnormal (jmc$job_management_id, jme$job_recovery_or_abort_set, 'RESTARTED', status);
        EXIT /jf_seg_open/; {----->
      IFEND;

{ The job recovery disposition indicated to continue.  If there is a failure now, the job abort disposition
{ will indicate what to do.

      IF old_ijlep^.queue_file_information.job_abort_disposition = jmc$restart_on_abort THEN
        job_recovery_disposition := jmc$restart_on_recovery;
      ELSE { jmc$terminate_on_abort
        job_recovery_disposition := jmc$terminate_on_recovery;
      IFEND;

      IF (old_ijlep^.job_damaged_during_recovery) OR (old_ijlep^.swap_data.swapping_io_error <>
            ioc$no_error) OR (jmc$dsw_io_error_while_swapped IN old_ijlep^.delayed_swapin_work) THEN

        osp$set_status_condition (sye$job_damaged, status);
        EXIT /jf_seg_open/; {----->
      IFEND;

      task_index := old_ijlep^.job_monitor_taskid.index;
      WHILE task_index > UPPERBOUND (tmv$ptl_p^) DO
        osp$expand_ptl ({ unconditionally_expand } TRUE, status);
        IF NOT status.normal THEN
          osp$set_status_condition (sye$jmtr_task_index_too_big, status);
          EXIT /jf_seg_open/; {----->
        IFEND;
      WHILEND;

      ijr_p := ^job_fixed^ [#OFFSET (^inhibit_job_recovery)];
      IF ijr_p^ <> 0 THEN
        STRINGREP (display_string, string_length, ' Inhibit recovery count ', ijr_p^);
        log (display_string (1, string_length));
        last_inhibit_job_recovery_p_p := ^job_fixed^ [#OFFSET (^last_inhibit_job_recovery_p)];
        display_address (last_inhibit_job_recovery_p_p^);
        display_xcb;
        osp$set_status_condition (sye$job_recovery_inhibited, status);
        EXIT /jf_seg_open/; {----->
      IFEND;

      attached_server_file_count_p := ^job_fixed^ [#OFFSET (^syv$attached_server_file_count)];
      IF (attached_server_file_count_p^ <> 0) AND NOT dfv$job_recovery_enabled THEN
        STRINGREP (display_string, string_length, ' Server file attach count ',
              attached_server_file_count_p^);
        log (display_string (1, string_length));
        osp$set_status_condition (sye$job_using_server_files, status);
        osp$append_status_integer (osc$status_parameter_delimiter, attached_server_file_count_p^, 10, FALSE,
              status);
        EXIT /jf_seg_open/; {----->
      IFEND;

      p_nosve_job_template := ^job_fixed^ [#OFFSET (^syv$nosve_job_template)];
      IF NOT p_nosve_job_template^ THEN
        osp$set_status_condition (sye$not_nosve_template, status);
        EXIT /jf_seg_open/; {----->
      IFEND;

      jrs_p := ^job_fixed^ [#OFFSET (^syv$job_recovery_step)];
      IF jrs_p^ = syc$jrs_initial_step THEN

{ ok

      ELSEIF jrs_p^ = syc$jrs_job_damaged_dont_rec THEN
        osp$set_status_condition (sye$job_damaged, status);
        EXIT /jf_seg_open/; {----->
      ELSE

{ update the copy in the job fixed array in case we need to write out all of the job
{ fixed pages later due to syp$update_flags.

        jrs_p^ := syc$jrs_initial_step;
        pn := #OFFSET (^syv$job_recovery_step) DIV osv$page_size;
        po := #OFFSET (^syv$job_recovery_step) - (pn * osv$page_size);
        jrs_p := #ADDRESS (1, swap_file_segn, (job_fixed_offset_list^ [pn] * osv$page_size) + po);
        jrs_p^ := syc$jrs_initial_step;
        mmp$write_modified_pages (jrs_p, #SIZE (jrs_p^), osc$wait, status);
        IF NOT status.normal THEN
          EXIT /jf_seg_open/; {----->
        IFEND;
      IFEND;

{ Validate temporary files of the job to make sure that all volumes are still
{ active in the system and that the disk space still looks like it is assigned
{ to the job.

      dmp$verify_job_volumes (jf_segnumber, volume_missing, unrecoverable_file);
      IF volume_missing THEN
        osp$set_status_condition (sye$volume_missing, status);
        EXIT /jf_seg_open/; {----->
      ELSEIF unrecoverable_file THEN
        osp$set_status_condition (sye$open_segs_not_recovered, status);
        EXIT /jf_seg_open/; {----->
      IFEND;

      status.normal := TRUE;

      IF (ijl_ord.block_number > jmv$ijl_p.max_block_in_use) OR
            (jmv$ijl_p.block_p^ [ijl_ord.block_number].index_p = NIL) THEN
        jmp$allocate_more_ijl_space (ijl_ord.block_number);
      IFEND;

      jmp$get_ijle_p (ijl_ord, ijlep);
      #SPOIL (ijlep);
      IF ijlep^.entry_status <> jmc$ies_entry_free THEN
        osp$set_status_condition (sye$ijl_entry_not_free, status);
        EXIT /jf_seg_open/; {----->
      IFEND;
      jmv$ijl_p.block_p^ [ijl_ord.block_number].in_use_count :=
            jmv$ijl_p.block_p^ [ijl_ord.block_number].in_use_count + 1;

{ update the copy in the job fixed array in case we need to write out all of the job
{ fixed pages later due to syp$update_flags.

      jip_p := ^job_fixed^ [#OFFSET (^jmv$jcb)];
      jip_p^.ijle_p := ijlep;
      jcb^.ijle_p := ijlep;
      mmp$write_modified_pages (jcb, #SIZE (jcb^), osc$wait, status);
      IF NOT status.normal THEN
        EXIT /jf_seg_open/; {----->
      IFEND;

    /ijl_created/
      BEGIN
        ijlep^ := old_ijlep^;
        ijlep^.ajl_ordinal := jmc$null_ajl_ordinal;
        ijlep^.kjl_ordinal := jcb^.job_id;
        ijlep^.swap_data.asid_reassigned_timestamp := 0;
        ijlep^.entry_status := jmc$ies_system_force_out;
        ijlep^.swap_status := jmc$iss_swapout_complete;
        ijlep^.next_swap_status := jmc$iss_null;
        ijlep^.inhibit_swap_count := 0;
        ijlep^.active_io_page_count := 0;
        ijlep^.active_io_requests := 0;
        ijlep^.executing_task_count := 0;
        ijlep^.swap_data.timestamp := #FREE_RUNNING_CLOCK (0);
        ijlep^.swap_data.swapout_timestamp := #FREE_RUNNING_CLOCK (0);
        ijlep^.swap_data.long_wait_expire_time := 0;
        ijlep^.swap_data.swap_file_length_in_pages := 0;
        ijlep^.job_scheduler_data.ready_task_link := jmv$null_ijl_ordinal;
        ijlep^.memory_reserve_request.swapout_job := FALSE;
        ijlep^.memory_reserve_request.requested_page_count := 0;
        ijlep^.memory_reserve_request.reserved_page_count := 0;
        ijlep^.interactive_task_gtid := tmv$null_global_task_id;
        ijlep^.delayed_swapin_work := $jmt$delayed_swapin_work
              [jmc$dsw_job_recovery, jmc$dsw_update_debug_lists, jmc$dsw_job_asid_changed,
              jmc$dsw_update_keypoint_masks, jmc$dsw_job_shared_asid_changed];

{  Give the job system dispatching priority with unlimited service to guarantee it will
{  swap in and recover.  The dispatching priority will be reset when recovery is complete.

        ijlep^.scheduling_dispatching_priority := jmc$priority_system_job;
        ijlep^.dispatching_control.dispatching_priority := jmc$priority_system_job;
        ijlep^.dispatching_control.service_remaining := jmc$dc_maximum_service_limit;
        FOR pqidi := LOWERVALUE (mmt$job_page_queue_index) TO UPPERVALUE (mmt$job_page_queue_index) DO
          ijlep^.job_page_queue_list [pqidi].count := 0;
          ijlep^.job_page_queue_list [pqidi].link.bkw := 0;
          ijlep^.job_page_queue_list [pqidi].link.fwd := 0;
        FOREND;
        gfp$get_segment_sfid (swap_file, ijlep^.swap_data.swap_file_sfid, status);
        IF NOT status.normal THEN
          EXIT /ijl_created/; {----->
        IFEND;

        pjxcbl := ^job_fixed^ [#OFFSET (^job_xcb_list)];
        xcb := pjxcbl^.head;
        j := 0;
        WHILE xcb <> NIL DO
          xcb := ^job_fixed^ [#OFFSET (xcb)];
          j := j + 1;
          IF j > tmc$maximum_ptl THEN
            osp$set_status_condition (sye$too_many_tasks_in_job, status);
            EXIT /ijl_created/; {----->
          IFEND;
          xcb := xcb^.link;
        WHILEND;

        IF j = 0 THEN
          osp$set_status_condition (sye$no_tasks_in_job, status);
          EXIT /ijl_created/; {----->
        IFEND;

        ALLOCATE jr_req.task_list_p: [1 .. j] IN osv$mainframe_wired_heap^;
        jr_req.reqcode := syc$rc_job_recovery_requests;
        jr_req.ijlo := ijl_ord;
        jr_req.subreq := syc$recover_ptl;
        j := 0;
        xcb := pjxcbl^.head;
        write_job_fixed := FALSE;

      /follow_xcb_chain/
        WHILE xcb <> NIL DO
          xcbo := #OFFSET (xcb);
          xcb := ^job_fixed^ [#OFFSET (xcb)];
          j := j + 1;
          WHILE xcb^.global_task_id.index > UPPERBOUND (tmv$ptl_p^) DO
            osp$expand_ptl ({ unconditionally_expand } TRUE, status);
            IF NOT status.normal THEN
              osp$set_status_condition (sye$utask_gtid_bad, status);
              EXIT /ijl_created/; {----->
            IFEND;
          WHILEND;
          IF xcb^.xp.p_register.pva.ring = 1 THEN
            display_xcb;
            osp$set_status_condition (sye$utask_in_ring_1, status);
            EXIT /ijl_created/; {----->
          ELSEIF xcb^.system_table_lock_count >= 256 THEN
            display_xcb;
            osp$set_status_condition (sye$utask_sys_tbl_lock_cnt, status);
            EXIT /ijl_created/; {----->
          ELSEIF xcb^.critical_task THEN
            display_xcb;
            osp$set_status_condition (sye$critical_task, status);
            EXIT /ijl_created/; {----->
          ELSEIF xcb^.system_error_count > 0 THEN
            display_xcb;
            osp$set_status_condition (sye$task_had_system_errors, status);
            EXIT /ijl_created/; {----->
          ELSEIF xcb^.xp.trap_enable <> osc$traps_enabled THEN
            display_xcb;
            osp$set_status_condition (sye$utask_traps_disabled, status);
            EXIT /ijl_created/; {----->
          IFEND;

{ Update active io counts in the IOCB (if there is one) so the job does not continue to wait
{ for io to complete after recovery.

          IF xcb^.iocb_p <> NIL THEN
            recover_iocb (^job_fixed^ [#OFFSET (xcb^.iocb_p)]);
            write_job_fixed := TRUE;
          IFEND;


{ Update the monitor and system flags if any from the ptl.  All of the job
{ fixed pages will be written out if flags are updated.

          IF NOT syv$system_was_idle THEN
            syp$update_flags (xcb, optlp, flags_updated);
            IF flags_updated THEN
              write_job_fixed := TRUE;
            IFEND;
          IFEND;
          jr_req.task_list_p^ [j].xcb_offset := xcbo;
          jr_req.task_list_p^ [j].dispatching_priority := jmc$priority_system_job;
          jr_req.task_list_p^ [j].gtid := xcb^.global_task_id;

{!      snap (' reqe', #LOC (jr_req.task_list_p^ [j]), #SIZE (jr_req.
{!            task_list_p^ [j]));

          xcb := xcb^.link;
        WHILEND /follow_xcb_chain/;

        IF write_job_fixed THEN
          syp$write_job_fixed_pages (pc, job_fixed, sfdp, status);
          IF NOT status.normal THEN
            EXIT /ijl_created/; {----->
          IFEND;
        IFEND;

        jr_req.count := j;
        ijlep^.statistics.ready_task_count := 0;
        ijlep^.statistics.tasks_not_in_long_wait := j;
        i#call_monitor (#LOC (jr_req), #SIZE (jr_req));
        IF NOT jr_req.status.normal THEN
          osp$set_status_abnormal ('SY', jr_req.status.condition, 'bad status from mtr', status);
          EXIT /ijl_created/; {----->
        ELSE
          status.normal := TRUE;
        IFEND;
      END /ijl_created/;

      IF jr_req.task_list_p <> NIL THEN
        FREE jr_req.task_list_p IN osv$mainframe_wired_heap^;
      IFEND;

{ If the system was processing in job mode at the time of a failure, then we
{ must discard the executing job (other than SYSTEM) because the running
{ exchange package was not recovered. To restart the job based on it's current
{ exchange package would restart the job backward in time which could cause
{ all kinds of problems especially if the job was writing a new file at the
{ time of the failure.


{ ****** This code only applies to Hot Backup recovery *****
{ ****** It will be reinstated with modifications when *****
{ ****** the 2000 system recovery is implemented.      *****
{   IF status.normal AND NOT syv$system_was_idle THEN
{     IF (oijlep^.swap_status = jmc$iss_executing) AND (oijlep^.ajl_ordinal <> 0) THEN
{       IF (oijlep^.ajl_ordinal = mtv$executing_ajl_at_failure [0]) OR
{             (oijlep^.ajl_ordinal = mtv$executing_ajl_at_failure [1]) THEN
{         osp$set_status_condition (sye$job_damaged, status);
{       IFEND;
{     IFEND;
{   IFEND;

      IF NOT status.normal THEN
        jmp$delete_ijl_entry (ijl_ord);
        IF syv$detailed_critical_displays >= syc$dcd_job_recovery_faildetail THEN
          dpp$put_critical_message (status.text.value (1, status.text.size), msg_status);
        IFEND
      ELSE

{ If the job recovered successfully, then indicate that it did.

        job_recovery_disposition := jmc$continue_on_recovery;
        syv$recovering_job_count := syv$recovering_job_count + 1;
        IF syv$recovering_job_count = 1 THEN
          mtv$saved_halt_cpu_ring_number := mtv$halt_cpu_ring_number;
          mtv$halt_cpu_ring_number := 0;
        IFEND;
      IFEND;

    END /jf_seg_open/;

    IF jf_segnumber <> 0 THEN
      mmp$invalidate_segment (jf_segnumber, 1, NIL, ost);
    IFEND;

  PROCEND syp$recover_job_r1;

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

{ PURPOSE:
{   The purpose of this routine is to clear the active io counts for any asynchronous io the
{   job may have had active, so that the job does not wait for the io to complete after recovery.
{ DESIGN:
{   All io requests that were active when the system went down are changed to complete,
{   (active_io_count = 0, condition = 0) with the io_already_active flag set.  The
{   io_already_active flag causes the io to be reissued when the job checks the status of
{   the io request.

  PROCEDURE recover_iocb
    (    iocb_p: ^mmt$io_control_block);

    VAR
      i: mmt$iocb_index;

    FOR i := LOWERBOUND (iocb_p^.iocb_table) TO iocb_p^.maximum_iocb_index_in_use DO
      IF (iocb_p^.iocb_table [i].active_io_count > 0) AND (iocb_p^.iocb_table [i].
            used_for_asynchronous_io) THEN
        iocb_p^.iocb_table [i].active_io_count := 0;
        iocb_p^.iocb_table [i].condition := 0;
        iocb_p^.iocb_table [i].io_already_active := TRUE;
      IFEND;
    FOREND;
  PROCEND recover_iocb;

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

{ PURPOSE:
{   The purpose of this routine is to free the job recovery statistic buffer.
{   If any jobs failed recovery, the JOB SCHEDULER task will mark them so they can never swap in.
{   It is called AFTER commit and start sched.

  PROCEDURE [XDCL, #GATE] syp$complete_job_recovery;

    VAR
      status: ost$status;

    IF syv$failure_reason_p <> NIL THEN
      FREE syv$failure_reason_p IN osv$mainframe_pageable_heap^;
    IFEND;

    IF syv$recovery_failure_count > 0 THEN
      jmv$job_scheduler_event [jmc$recovery_job_damaged] := TRUE;
      tmp$ready_system_task (tmc$stid_job_scheduler, status);
    IFEND;

  PROCEND syp$complete_job_recovery;
?? TITLE := 'PROCEDURE syp$mfh_for_job_recovery' ??
?? EJECT ??

  PROCEDURE [XDCL] syp$mfh_for_job_recovery;

{ The purpose of this procedure is to process the job recovery monitor flag.
{ It is the FIRST code to execute (in all tasks of a job) in a job during job
{recovery.

    VAR
      ijle_p: ^jmt$initiated_job_list_entry,
      tlock: [STATIC] ost$signature_lock,
      syv$jr_asid_nz,
      syv$jr_rcv_nr,
      syv$jr_rcv_req: [XDCL] integer := 0,
      psa: ^ost$stack_frame_save_area,
      gtid: ost$global_task_id,
      xcb: ^ost$execution_control_block,
      mlv$job_signon_count: [XREF] integer,
      sn,
      i: integer,
      str: string (72),
      new_sdt_p: ^mmt$segment_descriptor_table,
      request_block: mmt$rb_change_segment_table,
      sdte_p: ^mmt$segment_descriptor,
      sdtxe_p: ^mmt$segment_descriptor_extended,
      traps: 0 .. 3,
      ost,
      status: ost$status;

    PROCEDURE scch
      (    mf: ost$monitor_fault;
           ctc: ^ost$minimum_save_area;
       VAR continue: syt$continue_option);

      VAR
        status: ost$status;

      status.normal := TRUE;
      syp$process_job_rcv_failure (' job recovery condition handler invoked in syp$mfh_for_job_recovery',
            status);
    PROCEND scch;

    decrement_required := TRUE;
    i#enable_traps (traps);
    syp$establish_condition_handler (^scch);
    pmp$find_executing_task_xcb (xcb);

{This code is to verify the trapped (user) p_register.

    osp$set_signature_lock (tlock, osc$wait, ost);
    psa := #PREVIOUS_SAVE_AREA ();
    WHILE #SEGMENT (psa) = #SEGMENT (psa^.minimum_save_area.a2_previous_save_area) DO
      psa := psa^.minimum_save_area.a2_previous_save_area;
    WHILEND;
    psa := psa^.minimum_save_area.a2_previous_save_area;
    sn := psa^.minimum_save_area.p_register.pva.seg;
    sdte_p := mmp$get_sdt_entry_p (xcb, sn);
    sdtxe_p := mmp$get_sdtx_entry_p (xcb, sn);
    IF sdtxe_p^.sfid.residence = gfc$tr_system_wait_recovery THEN
      syv$jr_rcv_req := syv$jr_rcv_req + 1;
      IF sdte_p^.ste.asid <> 0 THEN
        syv$jr_asid_nz := syv$jr_asid_nz + 1;
      IFEND;
    ELSE
      syv$jr_rcv_nr := syv$jr_rcv_nr + 1;
    IFEND;
    osp$clear_signature_lock (tlock, ost);

    IF (xcb^.xp.segment_table_length * 8) > osv$page_size THEN
      ALLOCATE new_sdt_p: [0 .. xcb^.xp.segment_table_length] IN osv$job_fixed_heap^;
      mmp$free_pages (new_sdt_p, (xcb^.xp.segment_table_length * 8), osc$wait, status);
      mmp$assign_contiguous_memory (new_sdt_p, (xcb^.xp.segment_table_length * 8), status);
      IF NOT status.normal THEN
        syp$process_job_rcv_failure (' Unable to assign contiguous memory', status);
      IFEND;
      request_block.request_code := syc$rc_change_segment_table;
      request_block.new_sdt_offset := #OFFSET (new_sdt_p);
      request_block.new_sdtx_offset := 0;
      request_block.new_sdt_length := xcb^.xp.segment_table_length;
      i#call_monitor (#LOC (request_block), #SIZE (request_block));
      syp$set_status_from_mtr_status (request_block.status, status);
      IF NOT status.normal THEN
        syp$process_job_rcv_failure (' Problem changing the segment table', status);
      IFEND;
    IFEND;

    IF xcb = jmp$job_monitor_xcb () THEN

{ this is the jmtr task

      xcb := job_xcb_list.head;
      syv$job_task_count := 0;
      osp$initialize_signature_lock (job_task_count_lock, status);
      WHILE xcb <> NIL DO
        syv$job_task_count := syv$job_task_count + 1;
        xcb := xcb^.link;
      WHILEND;

      IF syv$job_recovery_step <> syc$jrs_test_sc_step THEN
        syv$job_recovery_step := syc$jrs_sc_step;

{ reconstruct jcb info as the first thing ...
{ lets hope this isnt too late.
{ Verify the ijl pointer in the jcb that was written from syp$recover_job_r1.

        jmp$get_ijle_p (jmv$jcb.ijl_ordinal, ijle_p);
        IF ijle_p <> jmv$jcb.ijle_p THEN
          osp$system_error (' job recovery -- ijl pointer mismatch', ^status);
        IFEND;
        jmv$jcb.job_id := jmv$jcb.ijle_p^.kjl_ordinal;
        pmv$task_template := jmv$task_private_templ_p;

{ Clear job recovery testing environment

        syv$test_jr_job := syv$test_jr_job - (-$syt$test_jr_set
              [syc$tjr_recursive_recovery, syc$tjr_fail_prior_jfr, fmc$tjr_recover_all_files,
              fmc$tjr_recovery_abort, syc$tjr_fail_post_jfr, syc$tjr_replace_sfid,
              syc$tjr_touch_unrec_segment]);

{ do system core recovery here

        dmp$recover_job_temp_file_space (status);

{ allow local file space recovery - we MAY want to prohibit local file
{ space recovery if ANY job fails in its file space recovery

        IF NOT status.normal THEN
          log ('Job file space conflict');
          syp$process_job_rcv_failure (' CANT RECOVER JOB TEMP FILE SPACE', status);
        IFEND;
        mlv$job_signon_count := 0;
        ofp$job_begin;

        syv$job_recovery_step := syc$jrs_jt_step;
      ELSE

{ testing job recovery in running system

        log ('In test job recovery');
        syv$job_recovery_step := syc$jrs_test_jt_step;
      IFEND;
    ELSE

{ tasks other than jmtr task

      WHILE syv$job_recovery_step < syc$jrs_jt_step DO
        pmp$delay (syv$job_recovery_wait_time, status);
      WHILEND;
    IFEND;

{ The pmp$set_system_flag call must be made with traps enabled
{ so that upon return to the trap sfsa, we return to the job
{ template trap handler, rather than user code.
{ The return MAY cause a page fault on
{ the sfsa p register, which, if it is a perm file, has not
{ yet been re-attached.

    pmp$get_executing_task_gtid (gtid);
    pmp$set_system_flag (syc$job_recovery_flag, gtid, status);
    IF NOT status.normal THEN
      osp$system_error (' job recovery set sys flag', ^status);
    IFEND;
    i#restore_traps (traps);
  PROCEND syp$mfh_for_job_recovery;
?? TITLE := 'PROCEDURE syp$replace_sfid', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$replace_sfid
    (    old_sfid: gft$system_file_identifier;
         new_sfid: gft$system_file_identifier;
         access_state: mmt$segment_access_state;
     VAR status: ost$status);

{ The purpose of this procedure is to replace one sfid with another (replace prior to
{ failure with recovered value after failure).  Each task's (in this job) sdtx is searched.

    VAR
      asti: mmt$ast_index,
      fde_p: gft$locked_file_desc_entry_p,
      i: integer,
      open_count: integer,
      rb: mmt$rb_ring1_segment_request,
      sdte_p: ^mmt$segment_descriptor,
      sdt_p: mmt$max_sdt_p,
      sdtxe_p: ^mmt$segment_descriptor_extended,
      sdtx_p: mmt$max_sdtx_p,
      temp_sfid: gft$system_file_identifier,
      xcb: ^ost$execution_control_block;

    status.normal := TRUE;
    IF syc$tjr_replace_sfid IN syv$test_jr_job THEN
      RETURN; {----->
    IFEND;
    xcb := job_xcb_list.head;


{ Only works for open global files.

    temp_sfid := old_sfid;
    temp_sfid.residence := gfc$tr_system_wait_recovery;

{ Call monitor to update ast sfid fields

    rb.reqcode := syc$rc_ring1_segment_request;
    rb.request := mmc$sr1_replace_sfid;
    asti := 0; {initialize to zero in case the real asti is not found (mtr will handle a zero asti)
    open_count := 0;
    WHILE xcb <> NIL DO
      mmp$get_max_sdt_sdtx_pointer (xcb, sdt_p, sdtx_p);
      FOR i := 0 TO xcb^.xp.segment_table_length DO
        sdte_p := ^sdt_p^.st [i];
        IF sdte_p^.ste.vl <> osc$vl_invalid_entry THEN
          sdtxe_p := ^sdtx_p^.sdtx_table [i];
          IF (sdtxe_p^.sfid = temp_sfid) THEN
            sdtxe_p^.sfid := new_sfid;
            asti := sdte_p^.asti;
            sdtxe_p^.access_state := access_state;
            open_count := open_count + 1;
          IFEND;
          IF (sdtxe_p^.shadow_info.shadow_segment_kind <> mmc$ssk_none) AND
                (sdtxe_p^.shadow_info.shadow_sfid = temp_sfid) THEN
            sdtxe_p^.shadow_info.shadow_sfid := new_sfid;
            open_count := open_count + 1;
          IFEND;
        IFEND;
      FOREND;
      xcb := xcb^.link;
    WHILEND;

{ Replace the SFID in the Active Segment Table (AST).

    rb.asti := asti;
    rb.old_sfid := temp_sfid;
    rb.new_sfid := new_sfid;
    mmp$issue_ring1_segment_request (rb);

{ Update the FDE open count.

    IF open_count <> 0 THEN
      gfp$get_locked_fde_p (new_sfid, fde_p);
      fde_p^.open_count := fde_p^.open_count + open_count;
      gfp$unlock_fde_p (fde_p);
    IFEND;

  PROCEND syp$replace_sfid;
?? TITLE := 'PROCEDURE syp$change_access_state', EJECT ??

{ The purpose of this procedure is to change the access_state in the SDTX for
{ a file. Each task's (in this job) sdtx is searched.

  PROCEDURE [XDCL, #GATE] syp$change_access_state
    (    sfid: gft$system_file_identifier;
         access_state: mmt$segment_access_state;
     VAR status: ost$status);


    VAR
      i: integer,
      sdt_p: mmt$max_sdt_p,
      sdte_p: ^mmt$segment_descriptor,
      sdtx_p: mmt$max_sdtx_p,
      sdtxe_p: ^mmt$segment_descriptor_extended,
      xcb: ^ost$execution_control_block;

    status.normal := TRUE;
    xcb := job_xcb_list.head;

  /for_all_tasks_in_job/
    WHILE xcb <> NIL DO

      mmp$get_max_sdt_sdtx_pointer (xcb, sdt_p, sdtx_p);

    /search_for_file/
      FOR i := 0 TO xcb^.xp.segment_table_length DO
        sdte_p := ^sdt_p^.st [i];
        IF sdte_p^.ste.vl <> osc$vl_invalid_entry THEN
          sdtxe_p := ^sdtx_p^.sdtx_table [i];
          IF (sdtxe_p^.sfid = sfid) THEN
            sdtxe_p^.access_state := access_state;
            IF access_state = mmc$sas_terminate_access THEN
              sdte_p^.ste.asid := 0;
            IFEND;
          IFEND;
        IFEND;
      FOREND /search_for_file/;
      xcb := xcb^.link;
    WHILEND /for_all_tasks_in_job/;

  PROCEND syp$change_access_state;
?? TITLE := 'PROCEDURE syp$invalidate_open_sfid', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$invalidate_open_sfid
    (    old_sfid: gft$system_file_identifier;
     VAR status: ost$status);

{ The purpose of this procedure is to invalidate the sfid of any
{ open segments with a given sfid.

    VAR
      i: integer,
      sdt_p: mmt$max_sdt_p,
      sdte_p: ^mmt$segment_descriptor,
      sdtx_p: mmt$max_sdtx_p,
      sdtxe_p: ^mmt$segment_descriptor_extended,
      temp_sfid: gft$system_file_identifier,
      xcb: ^ost$execution_control_block;

    status.normal := TRUE;
    xcb := job_xcb_list.head;
    temp_sfid := old_sfid;
    temp_sfid.residence := gfc$tr_system_wait_recovery;

    WHILE xcb <> NIL DO
      mmp$get_max_sdt_sdtx_pointer (xcb, sdt_p, sdtx_p);
      FOR i := 0 TO xcb^.xp.segment_table_length DO
        sdte_p := ^sdt_p^.st [i];
        IF sdte_p^.ste.vl <> osc$vl_invalid_entry THEN
          sdtxe_p := ^sdtx_p^.sdtx_table [i];

{ Check for both local/global and unrecovered sfid.

          IF (sdtxe_p^.sfid = temp_sfid) THEN
            sdte_p^.ste.vl := osc$vl_invalid_entry;
            sdtxe_p^.sfid := gfv$null_sfid;
          IFEND;
          IF (sdtxe_p^.shadow_info.shadow_segment_kind <> mmc$ssk_none) AND
                (sdtxe_p^.shadow_info.shadow_sfid = temp_sfid) THEN
            sdtxe_p^.shadow_info.shadow_segment_kind := mmc$ssk_none;
            sdtxe_p^.shadow_info.shadow_sfid := gfv$null_sfid;
          IFEND;
        IFEND;
      FOREND;
      xcb := xcb^.link;
    WHILEND;
  PROCEND syp$invalidate_open_sfid;
?? TITLE := 'PROCEDURE syp$verify_all_sfids_replaced', EJECT ??

  PROCEDURE syp$verify_all_sfids_replaced
    (VAR status: ost$status);

    VAR
      fde_p: gft$file_desc_entry_p,
      i: integer,
      local_status: ost$status,
      msg: string (50),
      ost: ost$status,
      sdt_p: mmt$max_sdt_p,
      sdte_p: ^mmt$segment_descriptor,
      sdtx_p: mmt$max_sdtx_p,
      sdtxe_p: ^mmt$segment_descriptor_extended,
      sl: integer,
      xcb: ^ost$execution_control_block;

    status.normal := TRUE;

    xcb := job_xcb_list.head;

    WHILE xcb <> NIL DO
      mmp$get_max_sdt_sdtx_pointer (xcb, sdt_p, sdtx_p);
      FOR i := 0 TO xcb^.xp.segment_table_length DO
        sdte_p := ^sdt_p^.st [i];
        IF sdte_p^.ste.vl <> osc$vl_invalid_entry THEN
          sdtxe_p := ^sdtx_p^.sdtx_table [i];
          IF (sdtxe_p^.sfid.residence = gfc$tr_system_wait_recovery) OR
                ((sdtxe_p^.shadow_info.shadow_segment_kind <> mmc$ssk_none) AND
                (sdtxe_p^.shadow_info.shadow_sfid.residence = gfc$tr_system_wait_recovery)) THEN
            IF syv$debug_job_recovery THEN
              syp$invoke_system_debugger ('Job recovery', 0, ost);
            IFEND;
            STRINGREP (msg, sl, 'Recovered segment conflict: ', #OFFSET (xcb): #(16), i: #(16));
            log (msg (1, sl));

{ Leave the sfid alone - so references to it can be trapped via residence.

            IF status.normal THEN
              osp$set_status_condition (sye$open_segs_not_recovered, status);
            IFEND;

          ELSEIF (sdtxe_p^.open_validating_ring_number <> 0) AND
                (mmc$sa_wired IN sdtxe_p^.software_attribute_set) THEN

{ Invalidate wired segments EXCEPT mainframe_wired and network_wired.

            sdte_p^.ste.vl := osc$vl_invalid_entry;
            sdtxe_p^.segment_reservation_state := mmc$srs_reserved;
          ELSE
            gfp$get_fde_p (sdtxe_p^.sfid, fde_p);
            dmp$increment_class_activity (fde_p);
          IFEND;
        IFEND;
      FOREND;
      xcb := xcb^.link;
    WHILEND;

  PROCEND syp$verify_all_sfids_replaced;
?? TITLE := 'PROCEDURE syp$push_inhibit_job_recovery', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$push_inhibit_job_recovery;

{ This procedure is called by the file system to indicate an operation is in
{progress
{ that does not (yet) allow job recovery.

    CONST
      initial_value = 0;

    TYPE
      sfsa_type = record
        fill1: 0 .. 0ffff(16),
        p: ^cell,
        a0: integer,
        a1: integer,
        fill2: 0 .. 0ffff(16),
        a2: ^sfsa_type, {previous save area pointer}
      recend;

    VAR
      actual_value: integer,
      sfsa_p: ^sfsa_type; {pointer to previous stack frame save area}

    ;

    osp$increment_locked_variable (inhibit_job_recovery, initial_value, actual_value);

{! For file system

    osp$begin_subsystem_activity;

    sfsa_p := #PREVIOUS_SAVE_AREA ();
    last_inhibit_job_recovery_p := sfsa_p^.p;

  PROCEND syp$push_inhibit_job_recovery;
?? TITLE := 'PROCEDURE syp$pop_inhibit_job_recovery', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$pop_inhibit_job_recovery;

{ This procedure is the converse of syp$push_inhibit_job_recovery

    CONST
      initial_value = 1;

    VAR
      actual_value: integer,
      error: boolean,
      status: ost$status;

    osp$decrement_locked_variable (inhibit_job_recovery, initial_value, actual_value, error);
    IF error THEN
      syp$invoke_system_debugger (' INHIBIT JOB RECOVERY CONFLICT ', 0, status);
    IFEND;

{! For file system

    osp$end_subsystem_activity;
  PROCEND syp$pop_inhibit_job_recovery;
?? TITLE := 'PROCEDURE syp$increment_server_file_count', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$increment_server_file_count;

    CONST
      initial_value = 0;

    VAR
      actual_value: integer;

    osp$increment_locked_variable (syv$attached_server_file_count, initial_value, actual_value);

  PROCEND syp$increment_server_file_count;
?? TITLE := 'PROCEDURE syp$decrement_server_file_count', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$decrement_server_file_count;

    CONST
      initial_value = 1;

    VAR
      actual_value: integer,
      error: boolean,
      status: ost$status;

    osp$decrement_locked_variable (syv$attached_server_file_count, initial_value, actual_value, error);
    IF error THEN
      syp$invoke_system_debugger (' ATTACHED SERVER FILE COUNT CONFLICT ', 0, status);
    IFEND;
  PROCEND syp$decrement_server_file_count;
?? TITLE := 'PROCEDURE syp$decrement_job_task_count', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$decrement_job_task_count;

{ This procedure keeps track of the number of tasks in a job
{ that have arrived at job template recovery.

    VAR
      status: ost$status;

    osp$set_signature_lock (job_task_count_lock, osc$wait, status);
    syv$job_task_count := syv$job_task_count - 1;
    osp$clear_signature_lock (job_task_count_lock, status);
  PROCEND syp$decrement_job_task_count;
?? TITLE := 'PROCEDURE syp$increment_file_rcv_failure', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$increment_file_rcv_failure;

{  This procedure increments the count of jobs that failed job recovery
{  due to file recovery failure.  The job was able to be terminated.

    VAR
      status: ost$status;

    osp$set_signature_lock (recovering_job_count_lock, osc$wait, status);
    syv$file_rcv_failure_count := syv$file_rcv_failure_count + 1;
    osp$clear_signature_lock (recovering_job_count_lock, status);
  PROCEND syp$increment_file_rcv_failure;

?? TITLE := 'PROCEDURE syp$terminate_unrecovered_job' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] syp$terminate_unrecovered_job
    (    ijl_ordinal: jmt$ijl_ordinal);

{ This procedure is called to get rid of any jobs we are trying to recover for which
{ the job or service class that the job was running in is no longer defined.

    VAR
      ijle_p: ^jmt$initiated_job_list_entry,
      job_class: jmt$job_class,
      kjl_ord: jmt$kjl_index,
      notify_scheduler_recovery_done: boolean,
      status: ost$status;

    jmp$get_ijle_p (ijl_ordinal, ijle_p);
    jmp$cleanup_unrecovered_job (ijl_ordinal);
    kjl_ord := ijle_p^.kjl_ordinal;
    jmp$delete_ijl_entry (ijl_ordinal);
    jmp$notify_queued_files_job_end (kjl_ord);

    osp$set_signature_lock (recovering_job_count_lock, osc$wait, status);
    syv$recovering_job_count := syv$recovering_job_count - 1;
    notify_scheduler_recovery_done := (syv$recovering_job_count = 0);
    osp$clear_signature_lock (recovering_job_count_lock, status);
    IF notify_scheduler_recovery_done THEN
      mtv$halt_cpu_ring_number := mtv$saved_halt_cpu_ring_number;
      mtv$saved_halt_cpu_ring_number := 0;
      jmv$refresh_job_candidates := TRUE;
      jmv$job_scheduler_event [jmc$examine_input_queue] := TRUE;
      jmv$job_scheduler_event [jmc$examine_swapin_queue] := TRUE;
      tmp$ready_system_task (tmc$stid_job_scheduler, status);
    IFEND;

  PROCEND syp$terminate_unrecovered_job;

?? TITLE := 'PROCEDURE syp$check_maxaj_and_ready_sched' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] syp$check_maxaj_and_ready_sched;

    VAR
      class: jmt$service_class_index,
      service_class_p: ^jmt$service_class_entry,
      str: string (60),
      strl: integer,
      status: ost$status;

{ 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.  The recoverable jobs all need to be able to swapin for job recovery to
{ complete, so if the maxaj is 0, raise it to 1.

    FOR class := jmc$system_service_class TO jmv$max_service_class_in_use DO
      service_class_p := jmv$service_classes [class];
      IF (service_class_p <> NIL) AND (service_class_p^.attributes.defined) AND
            (service_class_p^.attributes.maximum_active_jobs = 0) AND
            (jmv$job_counts.service_class_counts [class].swapped_jobs > 0) THEN
        service_class_p^.attributes.maximum_active_jobs := 1;
        str := '  ';
        STRINGREP (str, strl, ' MAXAJ FOR CLASS ', class, ' RAISED TO 1 FOR JOB RECOVERY');
        log (str);
      IFEND;
    FOREND;

    jmv$job_scheduler_event [jmc$ready_task_in_job] := TRUE;
    jmv$job_scheduler_event [jmc$recovery_swapin] := TRUE;
    jmv$job_scheduler_event [jmc$examine_swapin_queue] := TRUE;
    jmv$job_sched_events_selected [jmc$examine_swapin_queue] := TRUE;
    tmp$ready_system_task (tmc$stid_job_scheduler, status);

  PROCEND syp$check_maxaj_and_ready_sched;

?? TITLE := 'PROCEDURE syp$jt_recovery_complete' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] syp$jt_recovery_complete
    (VAR status: ost$status);

{ This procedure is called at the end of job template recovery for
{ a job.

    VAR
      str: string (60),
      i: integer,
      notify_scheduler_recovery_done: boolean,
      ost: ost$status;

    syp$verify_all_sfids_replaced (status);
    osp$set_signature_lock (recovering_job_count_lock, osc$wait, ost);
    IF decrement_required THEN
      syv$recovering_job_count := syv$recovering_job_count - 1;
      decrement_required := FALSE;
    IFEND;
    notify_scheduler_recovery_done := (syv$recovering_job_count = 0);
    osp$clear_signature_lock (recovering_job_count_lock, ost);
    syv$test_jr_job := $syt$test_jr_set [];
    syv$job_recovery_step := syc$jrs_recovery_complete;

    IF notify_scheduler_recovery_done THEN
      mtv$halt_cpu_ring_number := mtv$saved_halt_cpu_ring_number;
      mtv$saved_halt_cpu_ring_number := 0;
      jmv$refresh_job_candidates := TRUE;
      jmv$job_scheduler_event [jmc$examine_input_queue] := TRUE;
      jmv$job_scheduler_event [jmc$examine_swapin_queue] := TRUE;
      tmp$ready_system_task (tmc$stid_job_scheduler, ost);
    IFEND;

    IF NOT status.normal THEN
      syp$process_job_rcv_failure ('Segments(s) not recovered', status);
    IFEND;

  PROCEND syp$jt_recovery_complete;
?? TITLE := 'PROCEDURE syp$recover_volume_file_space' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] syp$recover_volume_file_space;

    CONST
      second = 1000000;

    VAR
      base: integer,
      clock: integer,
      display_update_interval: integer,
      log_msg: string (80),
      msg_len: integer,
      rb: mmt$rb_ring1_segment_request,
      str: string (60),
      strl: integer,
      ost: ost$status;

    base := 0;
    display_update_interval := dmv$ds_msg_update_interval * second;

    log (' Waiting to recover volume file space ');
    WHILE syv$recovering_job_count <> 0 DO

      IF dmv$display_recovery_messages THEN
        clock := #FREE_RUNNING_CLOCK (0);
        IF clock > (base + display_update_interval) THEN
          base := clock;
          STRINGREP (log_msg, msg_len, ' Recovering Jobs: ', syv$recovering_job_count: 6);
          log (log_msg (1, msg_len));
        IFEND;
      IFEND;

      pmp$delay (5000, ost);
    WHILEND;

    IF (syv$job_recovery_option = syc$jre_enabled) THEN
      syv$job_recovery_option := syc$jre_recovery_complete;
    IFEND;

{ Discard all PF pages not recovered.

{ The request to discard PF pages has been disabled for now, because of the
{ following problem:
{ If a job discovers that its environment is damaged when it runs its
{ recovery, it is marked as damaged and swapped out.  If it is at the
{ swapped_io_not_initiated state and PF pages are removed from its
{ job working set, then the count of pages that swapper thinks the job
{ has and the count actually in the jws are different.  This causes
{ the system to crash when the swapout advances.  It is too late in
{ job recovery to easily terminate the job when it discovers that its
{ environment is damaged.
{ The monitor request will count the number of files and pages that
{ are involved so that there will be a record in the job log.  No
{ pages are deleted though; the pages will be freed when the job swaps
{ all the way out to disk.

    rb.reqcode := syc$rc_ring1_segment_request;
    rb.request := mmc$sr1_end_job_recovery;
    mmp$issue_ring1_segment_request (rb);

    STRINGREP (str, strl, 'Unrecovered files = ', rb.unrecovered_files);
    log (str (1, strl));
    STRINGREP (str, strl, 'Unrecovered pages = ', rb.unrecovered_pages);
    log (str (1, strl));

    log (' Start returning unused temp file space.');
    dmp$return_temp_file_space;
    log (' Finished returning unused temp file space.');

  PROCEND syp$recover_volume_file_space;
?? TITLE := 'PROCEDURE syp$process_job_rcv_failure', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$process_job_rcv_failure
    (    msg: string ( * ),
         status: ost$status);

    VAR
      mmm: string (72),
      notify_scheduler_recovery_done: boolean,
      ost: ost$status,
      pijle: ^jmt$initiated_job_list_entry,
      sl: integer;

    syv$job_recovery_step := syc$jrs_job_damaged_dont_rec;
    syp$log_recovery_failure (msg, status);
    log (msg);

{ set ijl to indicate this is a "dead" job

    jmp$get_ijle_p (jmv$jcb.ijl_ordinal, pijle);
    pijle^.job_damaged_during_recovery := TRUE;
    IF (syv$debug_job_recovery) AND (status.normal OR ((NOT status.normal) AND
          (status.condition <> ose$path_table_locked))) THEN
      syp$invoke_system_debugger (msg, 0, ost);
    IFEND;
    osp$set_signature_lock (recovering_job_count_lock, osc$wait, ost);
    syv$recovery_failure_count := syv$recovery_failure_count + 1;
    IF decrement_required THEN
      syv$recovering_job_count := syv$recovering_job_count - 1;
      decrement_required := FALSE;
    IFEND;
    notify_scheduler_recovery_done := (syv$recovering_job_count = 0);
    osp$clear_signature_lock (recovering_job_count_lock, ost);

    IF notify_scheduler_recovery_done THEN
      mtv$halt_cpu_ring_number := mtv$saved_halt_cpu_ring_number;
      mtv$saved_halt_cpu_ring_number := 0;
      jmv$refresh_job_candidates := TRUE;
      jmv$job_scheduler_event [jmc$examine_input_queue] := TRUE;
      jmv$job_scheduler_event [jmc$examine_swapin_queue] := TRUE;
      tmp$ready_system_task (tmc$stid_job_scheduler, ost);
    IFEND;

    syv$job_recovery_wait_time := 100000000;
    WHILE TRUE DO
      pmp$delay (syv$job_recovery_wait_time, ost);
    WHILEND;
  PROCEND syp$process_job_rcv_failure;
?? TITLE := 'PROCEDURE [XDCL, #GATE] syp$log_recovery_failure', EJECT ??

{ PURPOSE:
{   This procedure inserts the reason for a job recovery failure into a buffer.  If
{   the reason is already in the buffer then just the reason count is incremented.

  PROCEDURE [XDCL, #GATE] syp$log_recovery_failure
    (    msg: string ( * );
         status: ost$status);

    VAR
      code_index: 0 .. syc$failure_condition_limit,
      err_index: 0 .. jmc$maximum_job_count,
      local_status: ost$status;

    IF syv$failure_reason_p = NIL THEN
      RETURN; {----->
    IFEND;

    osp$set_signature_lock (recovery_failure_lock, osc$wait, local_status);
    err_index := 1;
    WHILE ((syv$failure_reason_p^ [err_index].message <> msg) AND
          (syv$failure_reason_p^ [err_index].msg_count <> 0)) DO
      err_index := err_index + 1;
    WHILEND;
    syv$failure_reason_p^ [err_index].msg_count := syv$failure_reason_p^ [err_index].msg_count + 1;
    syv$failure_reason_p^ [err_index].message := msg;

  /log_condition/
    BEGIN
      code_index := 1;
      IF status.normal THEN
        EXIT /log_condition/; {----->
      IFEND;
      WHILE ((syv$failure_reason_p^ [err_index].conditions [code_index].code <> status.condition) AND
            (syv$failure_reason_p^ [err_index].conditions [code_index].code_count <> 0)) DO
        code_index := code_index + 1;
        IF code_index > syc$failure_condition_limit THEN
          EXIT /log_condition/; {----->
        IFEND;
      WHILEND;
      syv$failure_reason_p^ [err_index].conditions [code_index].code := status.condition;
      syv$failure_reason_p^ [err_index].conditions [code_index].
            code_count := syv$failure_reason_p^ [err_index].conditions [code_index].code_count + 1;
      IF (syv$failure_reason_p^ [err_index].conditions_count < code_index) THEN
        syv$failure_reason_p^ [err_index].conditions_count := code_index;
      IFEND;
    END /log_condition/;

    osp$clear_signature_lock (recovery_failure_lock, local_status);

  PROCEND syp$log_recovery_failure;
?? TITLE := 'PROCEDURE syp$begin_job_recovery', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$begin_job_recovery
    (    buffer_limit: 0 .. jmc$maximum_job_count);

    VAR
      ost: ost$status;

    osp$set_signature_lock (recovering_job_count_lock, osc$wait, ost);
    syv$recovering_job_count := 0;
    syv$recovery_failure_count := 0;
    syv$file_rcv_failure_count := 0;

    IF buffer_limit > 0 THEN
      ALLOCATE syv$failure_reason_p: [1 .. buffer_limit] IN osv$mainframe_pageable_heap^;
      pmp$zero_out_table (#LOC (syv$failure_reason_p^), #SIZE (syv$failure_reason_p^));
    IFEND;

  PROCEND syp$begin_job_recovery;
?? TITLE := 'PROCEDURE syp$end_job_recovery' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] syp$end_job_recovery;

    VAR
      ost: ost$status;

    osp$clear_signature_lock (recovering_job_count_lock, ost);
  PROCEND syp$end_job_recovery;
?? TITLE := 'PROCEDURE syp$job_recovery_from_image' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] syp$job_recovery_from_image
    (    swap_file: ^cell;
         jsn: jmt$system_supplied_name;
     VAR oijlep: ^jmt$initiated_job_list_entry;
     VAR recovery_disposition_available: boolean;
     VAR job_recovery_disposition: jmt$job_recovery_disposition;
     VAR status: ost$status);

    VAR
      am_page_count: integer,
      bi: integer,
      bn: integer,
      fde_p: gft$file_desc_entry_p,
      from_pc: ^mmt$active_segment_table_entry,
      jcbp: ^jmt$job_control_block,
      jcb_found: boolean,
      jcb_search: ^jmt$job_control_block,
      job_page_count: integer,
      new_ijle: jmt$initiated_job_list_entry,
      oajlep: ^jmt$active_job_list_entry,
      oastep: ^mmt$active_segment_table_entry,
      oijlo: jmt$ijl_ordinal,
      oijlxp: ^array [jmt$ijl_block_index] of jmt$initiated_job_list_entry,
      ost: ost$status,
      page_count: integer,
      pfti: integer,
      pps: ^ost$page_size,
      queue_id: mmt$job_page_queue_index,
      sfdo: integer,
      sfd_page_count: integer,
      spd_index: integer,
      sfd_p: ^jst$swap_file_descriptor,
      sfid: gft$system_file_identifier,
      sfsegn: ost$segment,
      swap_file_eoi: amt$file_byte_address,
      swap_file_offset: integer,
      swap_file_sfid: gft$system_file_identifier,
      to_offset: integer,
      to_pc: ^mmt$active_segment_table_entry,
      vpfi: integer,
      wait_count: integer;

    PROCEDURE scch
      (    mf: ost$monitor_fault;
           ctc: ^ost$minimum_save_area;
       VAR continue: syt$continue_option);

      osp$set_status_condition (sye$condition_encountered, status);
      EXIT syp$job_recovery_from_image; {----->
    PROCEND scch;

    status.normal := TRUE;
    IF syv$system_was_idle THEN
      oijlep := NIL;
      RETURN; {----->
    IFEND;

    syp$establish_condition_handler (^scch);
    status.normal := TRUE;

  /search_ijl/
    BEGIN
      FOR bn := LOWERBOUND (oijlp.block_p^) TO oijlp.max_block_in_use DO
        IF oijlp.block_p^ [bn].index_p <> NIL THEN
          oijlxp := #ADDRESS (1, rmfwsn, #OFFSET (oijlp.block_p^ [bn].index_p));
          FOR bi := LOWERBOUND (oijlxp^) TO UPPERBOUND (oijlxp^) DO
            IF oijlxp^ [bi].system_supplied_name = jsn THEN
              oijlo.block_number := bn;
              oijlo.block_index := bi;
              oijlep := ^oijlxp^ [bi];
              EXIT /search_ijl/; {----->
            IFEND;
          FOREND;
        IFEND;
      FOREND;
      osp$set_status_condition (sye$jsn_not_found_in_ijl, status);
      RETURN; {----->
    END /search_ijl/;

    CASE oijlep^.entry_status OF
    = jmc$ies_entry_free =
      osp$set_status_condition (sye$ijl_entry_free, status);
      RETURN; {----->
    = jmc$ies_job_in_memory_non_swap, jmc$ies_job_terminating =
      osp$set_status_condition (sye$ijl_non_swap, status);
      RETURN; {----->
    = jmc$ies_job_in_memory =

{ do nothing - continue

    = jmc$ies_swapin_in_progress, jmc$ies_job_swapped, jmc$ies_operator_force_out, jmc$ies_ready_task,
          jmc$ies_swapin_candidate =
      IF oijlep^.swap_status >= jmc$iss_swapout_io_complete THEN

        recovery_disposition_available := TRUE;
        job_recovery_disposition := oijlep^.queue_file_information.job_recovery_disposition;
        IF job_recovery_disposition = jmc$terminate_on_recovery THEN
          osp$set_status_abnormal (jmc$job_management_id, jme$job_recovery_or_abort_set, 'TERMINATED',
                status);
          RETURN; {----->
        ELSEIF job_recovery_disposition = jmc$restart_on_recovery THEN
          osp$set_status_abnormal (jmc$job_management_id, jme$job_recovery_or_abort_set, 'RESTARTED', status);
          RETURN; {----->
        IFEND;

{ The job recovery disposition indicated to continue.  If there is a failure now, the job abort disposition
{ will indicate what to do.

        IF oijlep^.queue_file_information.job_abort_disposition = jmc$restart_on_abort THEN
          job_recovery_disposition := jmc$restart_on_recovery;
        ELSE { jmc$terminate_on_abort
          job_recovery_disposition := jmc$terminate_on_recovery;
        IFEND;

        IF oijlep^.last_swap_status >= jmc$iss_swapout_io_complete THEN

{job swapped out - return ok

          status.normal := TRUE;
          RETURN; {----->
        IFEND;
      IFEND;
    ELSE
      osp$set_status_condition (sye$ijl_entry_status_bad, status);
      RETURN; {----->
    CASEND;

{ verify page queues with page frame table

    new_ijle := oijlep^;
    job_page_count := 0;
    IF oijlep^.sfd_p = NIL THEN
      sfdo := UPPERVALUE (integer);
    ELSE
      sfdo := #OFFSET (oijlep^.sfd_p);
    IFEND;
    FOR queue_id := LOWERVALUE (mmt$job_page_queue_index) TO UPPERVALUE (mmt$job_page_queue_index) DO
      new_ijle.swap_data.swapped_job_entry.job_page_queue_count [queue_id] :=
            oijlep^.job_page_queue_list [queue_id].count;
      page_count := oijlep^.job_page_queue_list [queue_id].count;
      job_page_count := job_page_count + page_count;
      pfti := oijlep^.job_page_queue_list [queue_id].link.bkw;
      vpfi := 0;

    /verify_pft/
      WHILE pfti <> 0 DO
        vpfi := vpfi + 1;
        IF vpfi > page_count THEN
          osp$set_status_condition (sye$too_many_pages_in_pft, status);
          RETURN; {----->
        IFEND;
        IF pfti > UPPERBOUND (opftp^) THEN
          osp$set_status_condition (sye$pfi_too_big, status);
          RETURN; {----->
        IFEND;
        IF opftp^ [pfti].pti > UPPERBOUND (oihtp^) THEN
          osp$set_status_condition (sye$pfi_too_big, status);
          RETURN; {----->
        IFEND;
        IF opftp^ [pfti].ijl_ordinal <> oijlo THEN
          osp$set_status_condition (sye$pft_ijlo_no_match, status);
          RETURN; {----->
        IFEND;
        oastep := opftp^ [pfti].aste_p;
        oastep := #ADDRESS (1, rmfwsn, #OFFSET (oastep));
        IF oastep^.in_use = FALSE THEN
          osp$set_status_condition (sye$aste_not_in_use, status);
          RETURN; {----->
        IFEND;
        IF oastep^.ijl_ordinal <> oijlo THEN
          IF ((oastep^.queue_id < mmc$pq_shared_first) OR (oastep^.queue_id > mmc$pq_shared_last)) THEN
            osp$set_status_condition (sye$aste_ijlo_no_match, status);
            RETURN; {----->
          IFEND;
        IFEND;

{ Get the fde pointer for permanent file pages; fde_p will be NIL for non-permanent files.  NIL fde_p
{ must be checked before dereferencing the pointer.

        gfp$get_fde_p_from_image (oastep^.sfid, rmfwsn, fde_p);

{ Special checks for invalid ws pages.  Discard swap file descriptor pages (they are job fixed pages
{ at a specific high offset).  Also discard locked permanent file pages and pages that are being read in.

        IF (opftp^ [pfti].locked_page = mmc$lp_page_in_lock) OR
              ((opftp^ [pfti].queue_id = mmc$pq_job_fixed) AND
              (opftp^ [pfti].sva.asid = oijlep^.job_fixed_asid) AND (opftp^ [pfti].sva.offset >= sfdo)) OR
              ((fde_p <> NIL) AND ((fde_p^.segment_lock.locked_for_write) OR
              (opftp^ [pfti].locked_page = mmc$lp_aging_lock))) THEN
          syv$discarded_page_count := syv$discarded_page_count + 1;
          job_page_count := job_page_count - 1;
          new_ijle.swap_data.swapped_job_entry.job_page_queue_count [queue_id] :=
                new_ijle.swap_data.swapped_job_entry.job_page_queue_count [queue_id] - 1;
        IFEND;
        pfti := opftp^ [pfti].link.bkw;
      WHILEND /verify_pft/;
      IF vpfi <> page_count THEN
        osp$set_status_condition (sye$too_few_pages_in_pft, status);
        RETURN; {----->
      IFEND;
    FOREND;
    am_page_count := 0;
    pfti := opqlp^ [mmc$pq_avail_modified].pqle.link.bkw;

  /vfy_am/
    WHILE pfti <> 0 DO
      IF pfti > UPPERBOUND (opftp^) THEN
        osp$set_status_condition (sye$pfi_too_big, status);
        RETURN; {----->
      IFEND;
      IF opftp^ [pfti].pti > UPPERBOUND (oihtp^) THEN
        osp$set_status_condition (sye$pfi_too_big, status);
        RETURN; {----->
      IFEND;
      IF opftp^ [pfti].ijl_ordinal <> oijlo THEN
        pfti := opftp^ [pfti].link.bkw;
        CYCLE /vfy_am/; {----->
      IFEND;
      oastep := opftp^ [pfti].aste_p;
      oastep := #ADDRESS (1, rmfwsn, #OFFSET (oastep));
      IF oastep^.in_use = FALSE THEN
        osp$set_status_condition (sye$aste_not_in_use, status);
        RETURN; {----->
      IFEND;
      IF oastep^.ijl_ordinal <> oijlo THEN
        IF ((oastep^.queue_id < mmc$pq_shared_first) OR (oastep^.queue_id > mmc$pq_shared_last)) THEN
          osp$set_status_condition (sye$aste_ijlo_no_match, status);
          RETURN; {----->
        IFEND;
      IFEND;

      gfp$get_fde_p_from_image (oastep^.sfid, rmfwsn, fde_p);

      IF (opftp^ [pfti].locked_page = mmc$lp_page_in_lock) OR
            ((opftp^ [pfti].queue_id = mmc$pq_job_fixed) AND (opftp^ [pfti].sva.asid =
            oijlep^.job_fixed_asid) AND (opftp^ [pfti].sva.offset >= sfdo)) OR
            ((fde_p <> NIL) AND ((fde_p^.segment_lock.locked_for_write) OR
            (opftp^ [pfti].locked_page = mmc$lp_aging_lock))) THEN
        pfti := opftp^ [pfti].link.bkw;
        CYCLE /vfy_am/; {----->
      IFEND;

      pfti := opftp^ [pfti].link.bkw;
      am_page_count := am_page_count + 1;
    WHILEND /vfy_am/;

    job_page_count := job_page_count + am_page_count;
    new_ijle.swap_data.swapped_job_entry.job_page_queue_count [mmc$pq_job_working_set] :=
          new_ijle.swap_data.swapped_job_entry.job_page_queue_count [mmc$pq_job_working_set] + am_page_count;
    sfsegn := #SEGMENT (swap_file);
    PUSH sfd_p: [0 .. 0]; {used to get size of a sfd with 1 entry}
    sfd_page_count := 1 + (#SIZE (sfd_p^) + #SIZE (jst$swapped_page_descriptor) * job_page_count - 1) DIV
          osv$page_size;
    WHILE ((job_page_count + sfd_page_count - 1) * #SIZE (jst$swapped_page_descriptor) + #SIZE (sfd_p^)) >
          (sfd_page_count * osv$page_size) DO
      sfd_page_count := sfd_page_count + 1;
    WHILEND;
    new_ijle.swap_data.swapped_job_entry.swap_file_descriptor_page_count := sfd_page_count;
    new_ijle.swap_data.swapped_job_entry.available_modified_page_count := 0;
    new_ijle.swap_data.swapped_job_page_count := job_page_count;

    PUSH sfd_p: [0 .. sfd_page_count + job_page_count - 1];
    gfp$get_segment_sfid (swap_file, sfid, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

{ do not wait for file space!

    wait_count := 5;
    REPEAT
      dmp$allocate_file_space_r1 (sfid, osv$page_size * (sfd_page_count + job_page_count), 0, 0, osc$nowait,
            sfc$no_limit, status);
      wait_count := wait_count - 1;
      IF NOT status.normal THEN
        pmp$delay (1000, ost);
      IFEND;
    UNTIL (status.normal) OR (wait_count = 0);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

{ EOI is set to zero to avoid reading pages from disk.

    dmp$set_eoi (sfid, 0, status);
    spd_index := 0;
    to_offset := 0;
    FOR queue_id := LOWERVALUE (mmt$job_page_queue_index) TO UPPERVALUE (mmt$job_page_queue_index) DO
      pfti := oijlep^.job_page_queue_list [queue_id].link.bkw;

    /swap_out/
      WHILE pfti <> 0 DO
        oastep := opftp^ [pfti].aste_p;
        oastep := #ADDRESS (1, rmfwsn, #OFFSET (oastep));

{ NOTE: Assumes oastep^.in_use = TRUE

        gfp$get_fde_p_from_image (oastep^.sfid, rmfwsn, fde_p);

        IF (opftp^ [pfti].locked_page = mmc$lp_page_in_lock) OR
              ((opftp^ [pfti].queue_id = mmc$pq_job_fixed) AND
              (opftp^ [pfti].sva.asid = oijlep^.job_fixed_asid) AND (opftp^ [pfti].sva.offset >= sfdo)) OR
              ((fde_p <> NIL) AND ((fde_p^.segment_lock.locked_for_write) OR
              (opftp^ [pfti].locked_page = mmc$lp_aging_lock))) THEN
          pfti := opftp^ [pfti].link.bkw;
          CYCLE /swap_out/; {----->
        IFEND;
        from_pc := #ADDRESS (1, image_segment_number, (pfti *
              osv$page_size) - recovery_load_offset + image_offset);
        to_pc := #ADDRESS (1, sfsegn, to_offset);
        i#move (from_pc, to_pc, osv$page_size);
        sfd_p^.swapped_page_descriptors [spd_index].pft_entry := opftp^ [pfti];
        sfd_p^.swapped_page_descriptors [spd_index].pft_entry.task_queue.head := 0;
        sfd_p^.swapped_page_descriptors [spd_index].pft_entry.task_queue.tail := 0;
        sfd_p^.swapped_page_descriptors [spd_index].pft_entry.aste_p := NIL;
        sfd_p^.swapped_page_descriptors [spd_index].page_table_entry.u := TRUE;
        sfd_p^.swapped_page_descriptors [spd_index].page_table_entry.v := TRUE;
        sfd_p^.swapped_page_descriptors [spd_index].page_table_entry.m := oihtp^ [opftp^ [pfti].pti];
        sfd_p^.swapped_page_descriptors [spd_index].entry_updated := FALSE;
        IF sfd_p^.swapped_page_descriptors [spd_index].pft_entry.active_io_count <> 0 THEN

{ If io is active, then it must be a write - force modified bit on

          sfd_p^.swapped_page_descriptors [spd_index].page_table_entry.m := TRUE;
        IFEND;
        IF (sfd_p^.swapped_page_descriptors [spd_index].page_table_entry.m) AND
              (opftp^ [pfti].locked_page = mmc$lp_not_locked) THEN
          sfd_p^.swapped_page_descriptors [spd_index].page_table_entry.v := TRUE;
        IFEND;

{ Make all unlocked pages in the job working set queue valid.  These may be invalid
{ if the previous system went down in certain areas of monitor's code.

        IF (queue_id = mmc$pq_job_working_set) AND (opftp^ [pfti].locked_page = mmc$lp_not_locked) THEN
          sfd_p^.swapped_page_descriptors [spd_index].page_table_entry.v := TRUE;
        IFEND;
        sfd_p^.swapped_page_descriptors [spd_index].pft_entry.active_io_count := 0;
        sfd_p^.swapped_page_descriptors [spd_index].ast_entry := oastep^;

        spd_index := spd_index + 1;
        to_offset := to_offset + osv$page_size;
        pfti := opftp^ [pfti].link.bkw;
      WHILEND /swap_out/;
    FOREND;
    pfti := opqlp^ [mmc$pq_avail_modified].pqle.link.bkw;

  /swap_am/
    WHILE pfti <> 0 DO
      IF opftp^ [pfti].ijl_ordinal <> oijlo THEN
        pfti := opftp^ [pfti].link.bkw;
        CYCLE /swap_am/; {----->
      IFEND;
      oastep := opftp^ [pfti].aste_p;
      oastep := #ADDRESS (1, rmfwsn, #OFFSET (oastep));

{ NOTE: Assumes oastep^.in_use = TRUE

      gfp$get_fde_p_from_image (oastep^.sfid, rmfwsn, fde_p);

      IF (opftp^ [pfti].locked_page = mmc$lp_page_in_lock) OR
            ((opftp^ [pfti].queue_id = mmc$pq_job_fixed) AND (opftp^ [pfti].sva.asid =
            oijlep^.job_fixed_asid) AND (opftp^ [pfti].sva.offset >= sfdo)) OR
            ((fde_p <> NIL) AND ((fde_p^.segment_lock.locked_for_write) OR
            (opftp^ [pfti].locked_page = mmc$lp_aging_lock))) THEN
        pfti := opftp^ [pfti].link.bkw;
        CYCLE /swap_am/; {----->
      IFEND;
      from_pc := #ADDRESS (1, image_segment_number, (pfti *
            osv$page_size) - recovery_load_offset + image_offset);
      to_pc := #ADDRESS (1, sfsegn, to_offset);
      i#move (from_pc, to_pc, osv$page_size);
      sfd_p^.swapped_page_descriptors [spd_index].pft_entry := opftp^ [pfti];
      sfd_p^.swapped_page_descriptors [spd_index].pft_entry.active_io_count := 0;
      sfd_p^.swapped_page_descriptors [spd_index].pft_entry.task_queue.head := 0;
      sfd_p^.swapped_page_descriptors [spd_index].pft_entry.task_queue.tail := 0;
      sfd_p^.swapped_page_descriptors [spd_index].entry_updated := FALSE;
      sfd_p^.swapped_page_descriptors [spd_index].pft_entry.aste_p := NIL;
      sfd_p^.swapped_page_descriptors [spd_index].pft_entry.queue_id := mmc$pq_job_working_set;
      sfd_p^.swapped_page_descriptors [spd_index].page_table_entry.u := TRUE;
      sfd_p^.swapped_page_descriptors [spd_index].page_table_entry.v := FALSE;

{ force pte valid and modified true because these pages age being put in the jws.

      sfd_p^.swapped_page_descriptors [spd_index].page_table_entry.m := TRUE;
      IF opftp^ [pfti].locked_page = mmc$lp_not_locked THEN
        sfd_p^.swapped_page_descriptors [spd_index].page_table_entry.v := TRUE;
      IFEND;
      sfd_p^.swapped_page_descriptors [spd_index].ast_entry := oastep^;

      spd_index := spd_index + 1;
      to_offset := to_offset + osv$page_size;
      pfti := opftp^ [pfti].link.bkw;
    WHILEND /swap_am/;

{ Move swap file descriptor pages to the swap file.

    sfd_p^.ijl_entry := new_ijle;
    sfd_p^.swapped_job_entry := new_ijle.swap_data.swapped_job_entry;
    jcb_found := FALSE;
    swap_file_offset := 0;
    gfp$get_segment_sfid (swap_file, 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_file), swap_file_offset);
      IF jcb_search^.jcb_identifier = 0FF00(16) THEN
        jcbp := 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_condition (sye$unable_to_locate_jcb, status);
          RETURN; {----->
        IFEND;
      IFEND;
    WHILEND;
    jcbp^.swapped_job_entry := new_ijle.swap_data.swapped_job_entry;
    i#move (#LOC (sfd_p^), #ADDRESS (1, sfsegn, to_offset), #SIZE (sfd_p^));
    mmp$write_modified_pages (swap_file, #SIZE (sfd_p^) + to_offset, osc$wait, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

{ double check

    IF jcbp^.system_name <> jsn THEN
      osp$set_status_condition (sye$jcb_jsn_no_match, status);
      RETURN; {----->
    IFEND;
    IF jcbp^.ijl_ordinal <> oijlo THEN
      osp$set_status_condition (sye$jcb_ijlo_no_match, status);
      RETURN; {----->
    IFEND;
  PROCEND syp$job_recovery_from_image;
?? TITLE := 'PROCEDURE syp$init_job_rec_from_image' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] syp$init_job_rec_from_image
    (VAR status: ost$status);

    VAR
      idle_status: ost$name,
      idle_status_seq_p: ^SEQ ( * ),
      image_descriptor: dst$nve_image_descriptor,
      job_recovery_is_enabled: boolean,
      job_recovery_status: string (8),
      job_recovery_status_seq_p: ^SEQ ( * ),
      oijlpp: ^jmt$ijl_p,
      oajlpp: ^^jmt$active_job_list,
      opftpp: ^^mmt$page_frame_table,
      optlpp: ^^tmt$primary_task_list,
      paa: ^^cell;

    PROCEDURE scch
      (    mf: ost$monitor_fault;
           ctc: ^ost$minimum_save_area;
       VAR continue: syt$continue_option);

      osp$set_status_condition (sye$condition_encountered, status);
      EXIT syp$init_job_rec_from_image; {----->
    PROCEND scch;

    syp$establish_condition_handler (^scch);
    status.normal := TRUE;

{ Fetch the idle status of the system from the RDF area.

    idle_status_seq_p := #SEQ (idle_status);
    dsp$get_data_from_rdf (dsc$rdf_system_idled_status, dsc$rdf_recovery, idle_status_seq_p);
    syv$system_was_idle := (idle_status = dsc$nve_idled);

    IF syv$system_was_idle THEN

{All jobs were swapped out if system was idle.

      RETURN; {----->
    IFEND;

{ Image file required from this point on !!!!!

    dsp$get_nve_image_description (image_descriptor);
    rmfwsn := #SEGMENT (image_descriptor.rcv_mainframe_wired_segment);

    recovery_load_offset := image_descriptor.rcv_load_offset;
    image_segment_number := #SEGMENT (image_descriptor.nve_image);
    image_offset := #OFFSET (image_descriptor.nve_image);

{!  snap ('rlo', #LOC (recovery_load_offset), #SIZE (recovery_load_offset));
{!  snap ('isn', #LOC (image_segment_number), #SIZE (image_segment_number));
{!  snap ('imgo', #LOC (image_offset), #SIZE (image_offset));

    oihtp := image_descriptor.rcv_hash_tbl_p;

    oijlpp := #ADDRESS (1, rmfwsn, #OFFSET (^jmv$ijl_p));
    oijlp := oijlpp^;

{!  snap ('oijlp', #LOC (oijlp), #SIZE (oijlp));

    IF (#RING (oijlp.block_p) <> 1) OR (#SEGMENT (oijlp.block_p) <> 1) OR (#OFFSET (oijlp.block_p) <= 0) THEN
      osp$set_status_condition (sye$ijl_offset_error, status);
      syv$job_recovery_option := syc$jre_system_disabled;
      RETURN; {----->
    IFEND;
    paa := #LOC (oijlp.block_p);
    i#build_adaptable_array_ptr (1, rmfwsn, #OFFSET (oijlp.block_p), #SIZE (oijlp.block_p^),
          LOWERBOUND (oijlp.block_p^), #SIZE (oijlp.block_p^ [1]), #LOC (paa^));

    oajlpp := #ADDRESS (1, rmfwsn, #OFFSET (^jmv$ajl_p));
    oajlp := oajlpp^;

{!  snap ('oajlp', #LOC (oajlp), #SIZE (oajlp));

    IF (#RING (oajlp) <> 1) OR (#SEGMENT (oajlp) <> 1) OR (#OFFSET (oajlp) <= 0) THEN
      osp$set_status_condition (sye$ajl_offset_error, status);
      syv$job_recovery_option := syc$jre_system_disabled;
      RETURN; {----->
    IFEND;
    paa := #LOC (oajlp);
    i#build_adaptable_array_ptr (1, rmfwsn, #OFFSET (oajlp), #SIZE (oajlp^), LOWERBOUND (oajlp^),
          #SIZE (oajlp^ [1]), #LOC (paa^));

    opftpp := #ADDRESS (1, rmfwsn, #OFFSET (^mmv$pft_p));
    opftp := opftpp^;

{!  snap ('opftp', #LOC (opftp), #SIZE (opftp));

    IF (#RING (opftp) <> 1) OR (#SEGMENT (opftp) <> 1) OR (#OFFSET (opftp) <= 0) THEN
      osp$set_status_condition (sye$pft_offset_error, status);
      syv$job_recovery_option := syc$jre_system_disabled;
      RETURN; {----->
    IFEND;
    paa := #LOC (opftp);
    i#build_adaptable_array_ptr (1, rmfwsn, #OFFSET (opftp), #SIZE (opftp^), LOWERBOUND (opftp^),
          #SIZE (opftp^ [LOWERBOUND (opftp^)]), #LOC (paa^));

    optlpp := #ADDRESS (1, rmfwsn, #OFFSET (^tmv$ptl_p));
    optlp := optlpp^;

{!  snap ('optlp', #LOC (optlp), #SIZE (optlp));

    IF (#RING (optlp) <> 1) OR (#SEGMENT (optlp) <> 1) OR (#OFFSET (optlp) <= 0) THEN
      osp$set_status_condition (sye$ptl_offset_error, status);
      syv$job_recovery_option := syc$jre_system_disabled;
      RETURN; {----->
    IFEND;
    paa := #LOC (optlp);
    i#build_adaptable_array_ptr (1, rmfwsn, #OFFSET (optlp), #SIZE (optlp^), LOWERBOUND (optlp^),
          #SIZE (optlp^ [1]), #LOC (paa^));

    opqlp := ^mmv$gpql;
    opqlp := #ADDRESS (1, rmfwsn, #OFFSET (opqlp));

  PROCEND syp$init_job_rec_from_image;
?? TITLE := 'PROCEDURE syp$test_job_recovery', EJECT ??

  PROCEDURE [XDCL] syp$test_job_recovery
    (    text: string ( * );
         id: dpt$window_id;
     VAR status: ost$status);

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

    wid := id;
    jmp$get_ijle_p (jmv$jcb.ijl_ordinal, ijlep);
    IF ijlep = NIL THEN
      status.normal := FALSE;
      RETURN; {----->
    IFEND;
    syv$job_recovery_step := syc$jrs_test_sc_step;
    ijlep^.delayed_swapin_work := ijlep^.delayed_swapin_work + $jmt$delayed_swapin_work
          [jmc$dsw_job_recovery];
    str := '  ';
    STRINGREP (str, i, 'Recovery test ', text);
    log (str);
    status.normal := TRUE;

{  force a swapout here to get job recovery started

    pmp$delay (10000, status);
  PROCEND syp$test_job_recovery;
?? TITLE := 'PROCEDURE syp$invoke_syscore_cond_handler', EJECT ??

  PROCEDURE [XDCL] syp$invoke_syscore_cond_handler;

    PROCEDURE handler_failed
      (    mf: ost$monitor_fault;
           continue: ^ost$minimum_save_area;
       VAR continue_option: syt$continue_option);

      hang_task (' R1 HANDLER FAILED ');
    PROCEND handler_failed;

    VAR
      mf: ost$monitor_fault,
      syv$number_of_sc_conds: [XDCL] integer := 0,
      psa: ^ost$minimum_save_area,
      processed: syt$continue_option,
      found: boolean;

    processed := syc$condition_ignored;
    syv$number_of_sc_conds := syv$number_of_sc_conds + 1;
    syp$establish_condition_handler (^handler_failed);
    psa := #PREVIOUS_SAVE_AREA ();
    get_monitor_fault (mf, found);
    IF found THEN
      invoke_handler (psa, mf, processed);
      IF processed = syc$condition_ignored THEN
        hang_task_no_handler (mf);
      IFEND;
    IFEND;
  PROCEND syp$invoke_syscore_cond_handler;
?? TITLE := 'PROCEDURE invoke_handler', EJECT ??

  PROCEDURE invoke_handler
    (    cpsa: ^ost$minimum_save_area;
         mf: ost$monitor_fault;
     VAR processed: syt$continue_option);

    VAR
      psa: ^ost$minimum_save_area,
      pc: cell,
      vfy: ^ost$pva,
      ped: ^syt$established_handler,
      csf: ^^syt$established_handler,
      traps: 0 .. 3;

    psa := cpsa;

  /search_for_handler/
    WHILE psa <> NIL DO
      IF (#RING (^pc) <> #RING (psa)) OR (#SEGMENT (^pc) <> #SEGMENT (psa)) THEN
        EXIT /search_for_handler/; {----->
      IFEND;
      IF psa^.frame_descriptor.on_condition_flag THEN
        vfy := #LOC (psa^.a1_current_stack_frame^);
        IF (vfy^.ring = #RING (^pc)) AND (vfy^.seg = #SEGMENT (^pc)) AND (vfy^.offset < #OFFSET (psa)) THEN
          csf := psa^.a1_current_stack_frame;
          ped := csf^;
          IF ped^.handler <> NIL THEN
            i#enable_traps (traps);
            ped^.handler^ (mf, psa, processed);
            i#restore_traps (traps);
            IF processed = syc$condition_processed THEN
              RETURN; {----->
            IFEND;
          ELSE
            hang_task (' bad established handler');
          IFEND;
        ELSE
          hang_task (' bad established handler');
        IFEND;
      IFEND;
      psa := #LOC (psa^.a2_previous_save_area^);
    WHILEND /search_for_handler/;
  PROCEND invoke_handler;
?? TITLE := 'PROCEDURE syp$invoke_syscore_ucr_handler', EJECT ??

  PROCEDURE [XDCL] syp$invoke_syscore_ucr_handler
    (    ucr: ost$user_conditions);

    PROCEDURE handler_failed
      (    mf: ost$monitor_fault;
           continue: ^ost$minimum_save_area;
       VAR continue_option: syt$continue_option);

      hang_task (' R1 HANDLER FAILED ');
    PROCEND handler_failed;

    VAR
      pscc: ^syt$system_core_condition,
      processed: syt$continue_option,
      psa: ^ost$minimum_save_area,
      mf: ost$monitor_fault;

    processed := syc$condition_ignored;
    syp$establish_condition_handler (^handler_failed);
    mf.identifier := syc$system_core_condition;
    pscc := #LOC (mf.contents);
    pscc^.condition := syc$ucr_condition;
    psa := #PREVIOUS_SAVE_AREA ();
    pscc^.sfsa := #LOC (psa^.a2_previous_save_area^);
    pscc^.ucr := ucr;

    invoke_handler (psa, mf, processed);
    IF processed = syc$condition_ignored THEN
      hang_task_no_handler (mf);
    IFEND;
  PROCEND syp$invoke_syscore_ucr_handler;
?? TITLE := 'PROCEDURE syp$cause_condition', EJECT ??

  PROCEDURE [XDCL] syp$cause_condition
    (    condition: syt$user_defined_condition);

    PROCEDURE handler_failed
      (    mf: ost$monitor_fault;
           continue: ^ost$minimum_save_area;
       VAR continue_option: syt$continue_option);

      hang_task (' R1 HANDLER FAILED ');
    PROCEND handler_failed;

    VAR
      pscc: ^syt$system_core_condition,
      processed: syt$continue_option,
      psa: ^ost$minimum_save_area,
      mf: ost$monitor_fault;

    processed := syc$condition_ignored;
    syp$establish_condition_handler (^handler_failed);
    mf.identifier := syc$system_core_condition;
    pscc := #LOC (mf.system_core_condition);
    pscc^.condition := syc$user_defined_condition;
    pscc^.user_defined_condition := condition;
    psa := #PREVIOUS_SAVE_AREA ();
    pscc^.sfsa := #LOC (psa^.a2_previous_save_area^);

    invoke_handler (psa, mf, processed);
  PROCEND syp$cause_condition;
?? TITLE := 'PROCEDURE syp$continue_to_cause', EJECT ??

  PROCEDURE [XDCL] syp$continue_to_cause
    (    mf: ost$monitor_fault;
         continue: ^ost$minimum_save_area;
         continue_option: syt$continue_option;
     VAR final_continue_option: syt$continue_option);

    PROCEDURE handler_failed
      (    mf: ost$monitor_fault;
           ctc: ^ost$minimum_save_area;
       VAR continue: syt$continue_option);

      hang_task (' R1 HANDLER FAILED ');
    PROCEND handler_failed;

    VAR
      psa: ^ost$minimum_save_area;

    IF continue_option = syc$condition_processed THEN
      final_continue_option := syc$condition_processed;
    IFEND;
    syp$establish_condition_handler (^handler_failed);
    psa := continue;
    IF psa <> NIL THEN
      psa := #LOC (psa^.a2_previous_save_area^);
      invoke_handler (psa, mf, final_continue_option);
    IFEND;

  PROCEND syp$continue_to_cause;
?? TITLE := 'PROCEDURE get_monitor_fault', EJECT ??

  PROCEDURE get_monitor_fault
    (VAR fault: ost$monitor_fault;
     VAR fault_found: boolean);

    VAR
      trap_enables: 0 .. 3,
      xcb: ^ost$execution_control_block,
      fault_status: tmt$fault_status,
      fault_index: 1 .. (tmc$maximum_monitor_faults + 1);

    fault_found := FALSE;
    fault_index := LOWERVALUE (tmt$monitor_fault_buffers);
    pmp$find_executing_task_xcb (xcb);
    i#disable_traps (trap_enables);

    WHILE NOT fault_found AND (fault_index <= UPPERVALUE (tmt$monitor_fault_buffers)) DO
      IF xcb^.monitor_faults.present [fault_index] THEN
        IF xcb^.monitor_faults.buffer [fault_index].pva.ring = 1 THEN
          tmp$get_monitor_fault (fault_index, fault, fault_status);
          CASE fault_status OF
          = tmc$normal_fault_status =
            fault_found := TRUE;
          = tmc$no_fault_present =
            ;
          = tmc$invalid_fault_index =
            ;
          ELSE
          CASEND;
        IFEND;
      IFEND;
      fault_index := fault_index + 1;
    WHILEND;
    i#restore_traps (trap_enables);
  PROCEND get_monitor_fault;
?? TITLE := 'PROCEDURE hang_task', EJECT ??

  PROCEDURE hang_task
    (    text: string ( * ));

    VAR
      xcb: ^ost$execution_control_block;

    pmp$find_executing_task_xcb (xcb);
    IF (xcb^.system_table_lock_count >= 256) OR (xcb^.critical_task) THEN
      osp$fatal_system_error (text, NIL);
    ELSE
      osp$check_for_job_recovery ('HUNG TASK during job recovery');
      syp$mfh_for_hang_task;
    IFEND;

  PROCEND hang_task;
?? TITLE := 'PROCEDURE hang_task_no_handler', EJECT ??

{  PURPOSE:   Procedure hang_task_no_handler
{  Is called to hang the task because a call to invoke a handler failed to find a handler.  If the
{  monitor fault is a broken task and the broken task ID is "system error", then osp$fatal_system_error is
{  called to stop the system and issue the text found in the broken task fault.  Otherwise the procedure
{  hang_task is called with a string.  For other broken task faults, the string identifies the broken task
{  fault.  If the monitor fault is not a broken task, the string will remain as "R1 CONDITION - NO HANDLER"
{
{   A monitor fault indicating that the permanent or temporary file space limit
{   has been exceeded will be ignored.  It is a non-fatal error in ring one.

  PROCEDURE hang_task_no_handler
    (    mf: ost$monitor_fault);

    VAR
      msg: string (71),
      broken_task: ^tmt$broken_task_monitor_fault,
      segment_access_condition: ^mmt$segment_access_condition;

    IF mf.identifier = tmc$broken_task_fault_id THEN
      broken_task := #LOC (mf.contents);
      msg := 'Broken Task ID= ';
      CASE broken_task^.broken_task_condition OF
      = tmc$btc_mntr_fault_buffer_full =
        msg (17, * ) := 'Monitor fault buffer full ';
      = tmc$btc_mf_traps_disabled =
        msg (17, * ) := 'Monitor fault traps disabled ';
      = tmc$btc_invalid_a0 =
        msg (17, * ) := 'Invalid A0 ';
      = tmc$btc_invalid_p =
        msg (17, * ) := 'Invalid P ';
      = tmc$btc_mcr_traps_disabled =
        msg (17, * ) := 'MCR traps disabled ';
      = tmc$btc_ucr_traps_disabled =
        msg (17, * ) := 'UCR traps disabled ';
      = tmc$btc_system_error =
        msg := broken_task^.text_p^;
      ELSE
      CASEND;
      hang_task (msg);
    ELSEIF mf.identifier = mmc$segment_fault_processor_id THEN
      segment_access_condition := #LOC (mf.contents);
      CASE segment_access_condition^.identifier OF
      = mmc$sac_pf_space_limit_exceeded, mmc$sac_tf_space_limit_exceeded =
        RETURN; {----->
      ELSE
      CASEND;
    IFEND;
    hang_task (' R1 CONDITION - NO HANDLER');

  PROCEND hang_task_no_handler;
?? TITLE := 'PROCEDURE syp$mfh_for_hang_task', EJECT ??

  PROCEDURE [XDCL] syp$mfh_for_hang_task;

    VAR
      ijlp: ^jmt$initiated_job_list_entry,
      xcb: ^ost$execution_control_block,
      status: ost$status;

    jmp$get_ijle_p (jmv$jcb.ijl_ordinal, ijlp);
    ijlp^.hung_task_in_job := TRUE;
    pmp$find_executing_task_xcb (xcb);

    syp$invoke_system_debugger ('Hung task', 0, status);

    WHILE TRUE DO
      syp$wait (tmc$infinite_wait);
      IF syc$mf_invoke_sysdebug IN xcb^.monitor_flags THEN
        xcb^.monitor_flags := xcb^.monitor_flags - $syt$monitor_flags [syc$mf_invoke_sysdebug];
        syp$invoke_system_debugger ('delayed hung task debug', 0, status);
      IFEND;
    WHILEND;

  PROCEND syp$mfh_for_hang_task;
?? TITLE := 'System Core Condition Handling Tests', EJECT ??
*copyc pmt$program_parameters

{Test mcr & non local exit

  PROCEDURE test_sc_ch1
    (    p: pmt$program_parameters;
     VAR status: ost$status);

    PROCEDURE sch
      (    mf: ost$monitor_fault;
           ctc: ^ost$minimum_save_area;
       VAR continue: syt$continue_option);

      log (' SC CH ENTERED');
      syp$continue_to_cause (mf, ctc, syc$condition_processed, continue);
      osp$set_status_abnormal ('YY', 88776, ' test ok ', status);
      EXIT test_sc_ch1; {----->
    PROCEND sch;

    VAR
      pc: ^cell,
      c: cell;

    status.normal := TRUE;
    IF mtv$halt_cpu_ring_number > 0 THEN
      log (' HALTRING MUST BE ZERO ');
      RETURN; {----->
    IFEND;
    syp$establish_condition_handler (^sch);
    pc := NIL;
    WHILE TRUE DO
      c := pc^;
    WHILEND;
  PROCEND test_sc_ch1;

{Test ucr & non local exit

  PROCEDURE test_sc_ch5
    (    p: pmt$program_parameters;
     VAR status: ost$status);

    PROCEDURE sch
      (    mf: ost$monitor_fault;
           ctc: ^ost$minimum_save_area;
       VAR continue: syt$continue_option);

      log (' SC CH ENTERED-UCR');
      syp$continue_to_cause (mf, ctc, syc$condition_processed, continue);
      osp$set_status_abnormal ('YY', 88776, ' test ok ', status);
      EXIT test_sc_ch5; {----->
    PROCEND sch;

    VAR
      i: integer;

    status.normal := TRUE;
    IF mtv$halt_cpu_ring_number > 0 THEN
      log (' HALTRING MUST BE ZERO ');
      RETURN; {----->
    IFEND;
    syp$establish_condition_handler (^sch);
    i := 10;
    WHILE TRUE DO
      i := i DIV 0;
    WHILEND;
  PROCEND test_sc_ch5;

{Test no handler - should fail

  PROCEDURE test_sc_ch2
    (    p: pmt$program_parameters;
     VAR status: ost$status);

    VAR
      pc: ^cell,
      c: cell;

    status.normal := TRUE;
    IF mtv$halt_cpu_ring_number > 0 THEN
      log (' HALTRING MUST BE ZERO ');
      RETURN; {----->
    IFEND;
    pc := NIL;
    WHILE TRUE DO
      c := pc^;
    WHILEND;
  PROCEND test_sc_ch2;

{Test handler failure - should fail

  PROCEDURE test_sc_ch3
    (    p: pmt$program_parameters;
     VAR status: ost$status);

    PROCEDURE sch
      (    mf: ost$monitor_fault;
           ctc: ^ost$minimum_save_area;
       VAR continue: syt$continue_option);

      log (' SC CH ENTERED');
      osp$set_status_abnormal ('YY', 88776, ' test failed ', status);
      pc := NIL;
      pc^ := c;
    PROCEND sch;

    VAR
      pc: ^cell,
      c: cell;

    status.normal := TRUE;
    IF mtv$halt_cpu_ring_number > 0 THEN
      log (' HALTRING MUST BE ZERO ');
      RETURN; {----->
    IFEND;
    syp$establish_condition_handler (^sch);
    pc := NIL;
    WHILE TRUE DO
      c := pc^;
    WHILEND;
  PROCEND test_sc_ch3;

{Test continue to cause - ignored - should fail

  PROCEDURE test_sc_ch6
    (    p: pmt$program_parameters;
     VAR status: ost$status);

    PROCEDURE sch
      (    mf: ost$monitor_fault;
           ctc: ^ost$minimum_save_area;
       VAR continue: syt$continue_option);

      log (' SC CH ENTERED');
      syp$continue_to_cause (mf, ctc, syc$condition_ignored, continue);
    PROCEND sch;

    VAR
      pc: ^cell,
      c: cell;

    status.normal := TRUE;
    IF mtv$halt_cpu_ring_number > 0 THEN
      log (' HALTRING MUST BE ZERO ');
      RETURN; {----->
    IFEND;
    syp$establish_condition_handler (^sch);
    pc := NIL;
    WHILE TRUE DO
      c := pc^;
    WHILEND;
  PROCEND test_sc_ch6;

{Test no continue - condition ignored by handler - should fail

  PROCEDURE test_sc_ch7
    (    p: pmt$program_parameters;
     VAR status: ost$status);

    PROCEDURE sch
      (    mf: ost$monitor_fault;
           ctc: ^ost$minimum_save_area;
       VAR continue: syt$continue_option);

      log (' SC CH ENTERED');
    PROCEND sch;

    VAR
      pc: ^cell,
      c: cell;

    status.normal := TRUE;
    IF mtv$halt_cpu_ring_number > 0 THEN
      log (' HALTRING MUST BE ZERO ');
      RETURN; {----->
    IFEND;
    syp$establish_condition_handler (^sch);
    pc := NIL;
    WHILE TRUE DO
      c := pc^;
    WHILEND;
  PROCEND test_sc_ch7;

{Test nested handlers and continue to cause

  PROCEDURE test_sc_ch4
    (    p: pmt$program_parameters;
     VAR status: ost$status);

    PROCEDURE b
      (VAR status: ost$status);

      PROCEDURE c
        (    mf: ost$monitor_fault;
             ctc: ^ost$minimum_save_area;
         VAR continue: syt$continue_option);

        VAR
          ost: ost$status;

        log (' in proc c');
        osp$set_status_abnormal ('zq', 939, ' b exited by c', status);
        log (' c doing continue');
        syp$continue_to_cause (mf, ctc, syc$condition_processed, continue);
        log (' continue returned to c');
        EXIT b; {----->
      PROCEND c;

      log (' in proc b ');
      syp$invoke_syscore_cond_handler;
      log (' invoke returned to b');
      syp$establish_condition_handler (^c);
      log (' proc b ready');
      z (status);
      log (' ERROR - b xqtd to much');
    PROCEND b;

    PROCEDURE z
      (VAR status: ost$status);

      PROCEDURE zc
        (    mf: ost$monitor_fault;
             ctc: ^ost$minimum_save_area;
         VAR continue: syt$continue_option);

        VAR
          ost: ost$status;

        log (' in proc zc');
        osp$set_status_abnormal ('zq', 993, ' z exited by zc', status);
        log (' zc doing continue');
        syp$continue_to_cause (mf, ctc, syc$condition_processed, continue);
        log (' ERROR - continue returned to zc');
        EXIT z; {----->
      PROCEND zc;

      VAR
        pc: ^cell,
        c: cell;

      log (' in proc z ');
      syp$establish_condition_handler (^zc);
      log (' proc z ready');
      pc := NIL;
      pc^ := c;
      log (' ERROR - z xqtd to much');
    PROCEND z;

    VAR
      ost: ost$status;

    IF mtv$halt_cpu_ring_number > 0 THEN
      log (' HALTRING MUST BE ZERO ');
      RETURN; {----->
    IFEND;
    b (status);
    log (' return from b to a');
  PROCEND test_sc_ch4;

  TYPE
    zzzz = (job, system);

?? TITLE := 'PROCEDURE syp$set_job_recovery_test', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$set_job_recovery_test
    (    t: zzzz;
         option: 0 .. 255);

    IF syv$allow_jr_test THEN
      IF t = job THEN
        syv$test_jr_job := syv$test_jr_job + $syt$test_jr_set [option];
      ELSE
        syv$test_jr_system := syv$test_jr_system + $syt$test_jr_set [option];
      IFEND;
    IFEND;

  PROCEND syp$set_job_recovery_test;

?? TITLE := 'PROCEDURE syp$set_system_idling', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$set_system_idling
    (    system_is_idling: boolean);

    syv$system_is_idling := system_is_idling;
  PROCEND syp$set_system_idling;


?? TITLE := 'PROCEDURE syp$system_is_idling', EJECT ??

  FUNCTION [XDCL, #GATE] syp$system_is_idling: boolean;

    syp$system_is_idling := syv$system_is_idling;
  FUNCEND syp$system_is_idling;

?? TITLE := 'PROCEDURE syp$clear_job_recovery_test', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$clear_job_recovery_test
    (    t: zzzz;
         option: 0 .. 255);

    IF (option < 0) OR (option > 255) THEN
      RETURN; {----->
    IFEND;
    IF t = job THEN
      syv$test_jr_job := syv$test_jr_job - $syt$test_jr_set [option];
    ELSE
      syv$test_jr_system := syv$test_jr_system - $syt$test_jr_set [option];
    IFEND;

  PROCEND syp$clear_job_recovery_test;
?? TITLE := 'PROCEDURE syp$increment_avt_r1', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$increment_avt_r1
    (    sfid: gft$system_file_identifier);

    VAR
      fde_p: gft$file_desc_entry_p;

    gfp$get_fde_p (sfid, fde_p);
    dmp$increment_class_activity (fde_p);

  PROCEND syp$increment_avt_r1;
?? TITLE := 'PROCEDURE syp$disable_job_recovery', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$disable_job_recovery;

    VAR
      job_recovery_status: string (8);

    IF (syv$job_recovery_option = syc$jre_enabled) THEN
      syv$job_recovery_option := syc$jre_system_disabled;
    IFEND;

    job_recovery_status := 'disable';
    dsp$store_data_in_rdf (dsc$rdf_job_recovery, dsc$rdf_production, #SEQ (job_recovery_status));
    log ('Job recovery disabled by the system');

  PROCEND syp$disable_job_recovery;
?? TITLE := 'PROCEDURE syp$enable_job_recovery', EJECT ??

  PROCEDURE [XDCL] syp$enable_job_recovery;

    VAR
      job_recovery_status: string (8);

    { Once job recovery has been disabled, variable syv$job_recovery_option should not be set
    { back to syc$jre_enabled.  This is because Device Manager releases temporary file space
    { when a volume is recovered, if syv$job_recovery_option says job recovery is not enabled.
    { Once temporary file space has been released, job recovery is impossible during the current
    { deadstart.  Also, if syv$job_recovery_option is not left at syc$jre_recovery_complete,
    { temporary file space will not be released properly if a volume is turned on after deadstart.

    job_recovery_status := 'enable';
    dsp$store_data_in_rdf (dsc$rdf_job_recovery, dsc$rdf_production, #SEQ (job_recovery_status));

  PROCEND syp$enable_job_recovery;
?? TITLE := 'PROCEDURE mtp$error_stop', EJECT ??

  PROCEDURE [XDCL] mtp$error_stop
    (    str: string ( * ));

    osp$system_error (str, NIL);

  PROCEND mtp$error_stop;
?? TITLE := 'PROCEDURE [XDCL] syp$terminate_task', EJECT ??

  PROCEDURE [XDCL] syp$terminate_task
    (    termination_reason: ost$ring1_termination_reason);

    VAR
      status: ost$status,
      xcb_p: ^ost$execution_control_block;

    pmp$find_executing_task_xcb (xcb_p);
    xcb_p^.ring1_termination_reason := termination_reason;
    pmp$set_system_flag (pmc$sf_terminate_task, xcb_p^.global_task_id, status);

  PROCEND syp$terminate_task;
?? TITLE := 'PROCEDURE syp$get_job_swap_status', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$get_job_swap_status
    (    ijl_ordinal: jmt$ijl_ordinal;
     VAR swapped_out: boolean);

    VAR
      initialized: [STATIC] boolean := FALSE,
      all_swapped: [STATIC] boolean := FALSE,
      status: ost$status,
      oijlxp: ^array [jmt$ijl_block_index] of jmt$initiated_job_list_entry;

    swapped_out := TRUE;

    IF NOT initialized THEN
      initialized := TRUE;
      syp$init_job_rec_from_image (status);
      IF NOT status.normal THEN
        all_swapped := TRUE;
        RETURN; {----->
      IFEND;
    IFEND;

    IF all_swapped OR syv$system_was_idle THEN
      RETURN; {----->
    IFEND;

    IF oijlp.block_p <> NIL THEN
      IF oijlp.block_p^ [ijl_ordinal.block_number].index_p <> NIL THEN
        oijlxp := #ADDRESS (1, rmfwsn, #OFFSET (oijlp.block_p^ [ijl_ordinal.block_number].index_p));
        IF oijlxp^ [ijl_ordinal.block_index].entry_status > jmc$ies_entry_free THEN
          IF oijlxp^ [ijl_ordinal.block_index].swap_status < jmc$iss_swapout_complete THEN
            swapped_out := FALSE;
          IFEND;
        IFEND;
      IFEND;
    IFEND;

  PROCEND syp$get_job_swap_status;

?? TITLE := 'PROCEDURE syp$recover_executing_ajl_ord', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$recover_executing_ajl_ord;


    VAR
      image_descriptor: dst$nve_image_descriptor,
      rmfwsn: ost$segment, {recoverd mainframe wired segment number}
      system_core_id: ^ost$name,
      ajl_ord_base: ^integer;

    VAR
      syv$recovery_override: [XREF] 0 .. 0ff(16);

    dsp$get_nve_image_description (image_descriptor);
    IF (image_descriptor.rcv_mainframe_wired_segment <> NIL) THEN
      rmfwsn := #SEGMENT (image_descriptor.rcv_mainframe_wired_segment);
      IF (image_descriptor.rcv_page_size = osv$page_size) THEN

        { Image file required from this point on !!!!!

        system_core_id := #ADDRESS (1, rmfwsn, #OFFSET (^jmv$system_core_id));
        IF (system_core_id^ = jmv$system_core_id) OR (syv$recovery_override <> 0) THEN
          ajl_ord_base := #ADDRESS (1, rmfwsn, #OFFSET (^mtv$processor_mode [0]));
          mtv$executing_ajl_at_failure [0] := ajl_ord_base^;
          ajl_ord_base := #ADDRESS (1, rmfwsn, #OFFSET (^mtv$processor_mode [1]));
          mtv$executing_ajl_at_failure [1] := ajl_ord_base^;

        IFEND;
      IFEND;
    IFEND;

  PROCEND syp$recover_executing_ajl_ord;

?? OLDTITLE ??
?? NEWTITLE := '[xdcl, #gate] SYP$TEST_CONDITION_HANDLER', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$test_condition_handler
    (    monitor_fault: ost$monitor_fault);

    VAR
      pscc: ^syt$system_core_condition,
      processed: syt$continue_option,
      psa: ^ost$minimum_save_area;

?? NEWTITLE := 'HANDLER_FAILED', EJECT ??

    PROCEDURE handler_failed
      (    mf: ost$monitor_fault;
           continue: ^ost$minimum_save_area;
       VAR continue_option: syt$continue_option);

      hang_task (' R1 HANDLER FAILED ');

    PROCEND handler_failed;
?? OLDTITLE ??
?? EJECT ??

    processed := syc$condition_ignored;
    syp$establish_condition_handler (^handler_failed);
    psa := #PREVIOUS_SAVE_AREA ();

    invoke_handler (psa, monitor_fault, processed);

  PROCEND syp$test_condition_handler;
{Debug code
?? TITLE := 'PROCEDURE syp$increment_rsv_cycle_counter', EJECT ??

  PROCEDURE [XDCL, #GATE] syp$increment_rsv_cycle_counter
    (    counter_type: (syc$ircc_detach_nil, syc$ircc_detach_purged, syc$ircc_reattach_purged));

{ This procedure is called by the file system to indicate a situation, where
{ we seem to run into attachment problems. This code is only for debug purposes.

    CONST
      initial_value = 0;

    VAR
      actual_value: integer;

    CASE counter_type OF
    = syc$ircc_detach_nil =
      osp$increment_locked_variable (syv$detach_nil_rsv_cycle_count, initial_value, actual_value);
    = syc$ircc_detach_purged =
      osp$increment_locked_variable (syv$detach_purged_rsv_cyc_count, initial_value, actual_value);
    = syc$ircc_reattach_purged =
      osp$increment_locked_variable (syv$reattach_purged_rsv_cyc_cnt, initial_value, actual_value);
    ELSE
    CASEND;

  PROCEND syp$increment_rsv_cycle_counter;
{End Debug code

MODEND sym$job_recovery_r1;
