?? LEFT := 1, RIGHT := 110 ??
?? NEWTITLE := 'JSM$JOB_SWAPPER' ??
MODULE jsm$job_swapper {JSMJS} ;

{
{   The purpose of this module is to swap jobs in and out.  When this
{ module called the job should be in an idle state.  Swapping a job is
{ the process of collecting all of the pages of the job currently in
{ memory and writing them to mass storage along with the information
{ necessary to read job from mass storage and put into state such that
{ execution may proceed.  Swapping a job in is the process of moving the
{ job image from mass storage back into memory.
{

?? PUSH (LISTEXT := ON) ??
*copyc dmt$error_condition_codes
*copyc dmt$minimum_allocation_unit
*copyc jmt$active_job_list
*copyc jmt$ajl_ordinal
*copyc jmt$swapped_job_entry
*copyc jse$condition_codes
*copyc jst$rb_job_swapping_functions
*copyc jst$swap_state_statistics
*copyc jst$swap_file_descriptor
*copyc jmt$initiated_job_list_entry
*copyc jmt$ijl_ordinal
*copyc ioe$st_errors
*copyc ost$status
*copyc sft$file_space_limit_kind
*copyc syc$monitor_request_codes
?? POP ??



{  External procedures called by this module.

*copyc dmp$allocate_file_space_r1
*copyc dmp$file_on_down_volume
*copyc dmp$reallocate_file_space
*copyc dmp$reassign_file
*copyc dmp$set_eoi
*copyc i#call_monitor
*copyc jmp$get_ijle_p
*copyc lgp$add_entry_to_system_log
*copyc pmp$delay
*copyc syp$set_status_from_mtr_status


{  Global variables referenced by this module.

*copyc jmv$ijl_p
*copyc jmv$null_ijl_ordinal
*copyc jsv$ijl_swap_queue_list
*copyc jsv$swap_state_statistics
*copyc osv$page_size
?? TITLE := 'ISSUE_MONITOR_REQUEST' ??
?? EJECT ??
{
{     The purpose of this procedure is to issue a monitor request to perform swapping functions
{  that require none of the variants in the request block.
{

  PROCEDURE [INLINE] issue_monitor_request
    (    ijl_ordinal: jmt$ijl_ordinal;
         subfunction: jst$job_swapping_subfunctions;
     VAR status: ost$status);


    VAR
      request_block: jst$rb_job_swapping_functions;


    request_block.reqcode := syc$rc_job_swapping_functions;
    request_block.ijl_ordinal := ijl_ordinal;
    request_block.subfunction := subfunction;

    i#call_monitor (#LOC (request_block), #SIZE (request_block));

    syp$set_status_from_mtr_status (request_block.status, status);

  PROCEND issue_monitor_request;

?? TITLE := 'JSP$ADVANCE_LONG_WAIT_SWAP', EJECT ??

  PROCEDURE [XDCL, #GATE] jsp$advance_long_wait_jobs
    (    flush_all_pages: boolean;
     VAR pages_flushed_from_lw_queue: mmt$page_frame_index);

{ The purpose of this procedure is to advance the swapping of jobs in the long wait
{ queue until the specified amount of memory is freed.

    VAR
      request_block: jst$rb_job_swapping_functions;

    request_block.reqcode := syc$rc_job_swapping_functions;
    request_block.ijl_ordinal := jmv$null_ijl_ordinal;
    request_block.subfunction := jsc$jss_initiate_swapout_io;
    request_block.flush_all_pages := flush_all_pages;

    i#call_monitor (#LOC (request_block), #SIZE (request_block));

    pages_flushed_from_lw_queue := request_block.pages_flushed;

  PROCEND jsp$advance_long_wait_jobs;

?? TITLE := '[XDCL] jsp$help_monitor_mode_swapper', EJECT ??

  PROCEDURE [XDCL] jsp$help_monitor_mode_swapper;

{
{     The purpose of this procedure is to do some work for the monitor mode swapper that it
{  can not do itself.  There will be certain situations when the swap file can not be
{  allocated in monitor mode, or the swap file may need to be reassigned if it is on a downed
{  volume.
{
{ Check if the volume is down.  Reassign the swap file if it is, otherwise wait and try to allocate again.

    TYPE
      message_type = (jsc$mt_reassign_file, jsc$mt_report_status);

    PROCEDURE log_message
      (    request: message_type;
           ijle_p: ^jmt$initiated_job_list_entry);

      VAR
        ignore_status: ost$status,
        log_time: ost$time,
        msg: string (80);

      msg (1, *) := ' ';
      IF request = jsc$mt_reassign_file THEN
        msg (1, 37) := 'Attempt to reassign swap file of job ';
        msg (38, 31) := ijle_p^.system_supplied_name;
      ELSE
        IF ijle_p^.swap_data.swapping_io_error = ioc$unrecovered_error_unit_down THEN
          msg (1, 48) := 'Unable to reassign swap file. Abandoned swap of ';
        ELSE
          msg (1, 48) := 'Unable to allocate swap file. Abandoned swap of ';
        IFEND;
        msg (49, 31) := ijle_p^.system_supplied_name;
      IFEND;
      lgp$add_entry_to_system_log (pmc$msg_origin_system, msg, log_time, ignore_status);
    PROCEND log_message;

?? TITLE := '[XDCL, #GATE] jsp$help_monitor_mode_swapper', EJECT ??


    VAR
      file_reassigned: boolean,
      fix_swap_file_pass: 0 .. 10,
      ijl_bn: jmt$ijl_block_number,
      ijl_bi: jmt$ijl_block_index,
      ijle_p: ^jmt$initiated_job_list_entry,
      ijl_ordinal: jmt$ijl_ordinal,
      local_status: ost$status,
      file_on_down_volume: boolean,
      status: ost$status,
      total_swapped_page_count: integer;

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

      /search_for_job_2/
        FOR ijl_bi := LOWERVALUE (jmt$ijl_block_index) TO UPPERVALUE (jmt$ijl_block_index) DO
          ijl_ordinal.block_number := ijl_bn;
          ijl_ordinal.block_index := ijl_bi;
          ijle_p := ^jmv$ijl_p.block_p^ [ijl_bn].index_p^ [ijl_bi];
          fix_swap_file_pass := 0;
          file_reassigned := FALSE;

        /fix_swap_file/
          REPEAT
            fix_swap_file_pass := fix_swap_file_pass + 1;
            CASE ijle_p^.swap_status OF
            = jmc$iss_job_allocate_swap_file, jmc$iss_swapped_io_cannot_init =
              CASE ijle_p^.swap_data.swapping_io_error OF

              = ioc$allocate_file_space =
                total_swapped_page_count := ijle_p^.swap_data.swapped_job_page_count +
                      ijle_p^.swap_data.swapped_job_entry.swap_file_descriptor_page_count;
                IF ijle_p^.swap_data.swap_file_length_in_pages < total_swapped_page_count THEN
                  dmp$allocate_file_space_r1 (ijle_p^.swap_data.swap_file_sfid,
                     0, (total_swapped_page_count * osv$page_size), 0, osc$nowait,
                     sfc$no_limit, status);
                  IF NOT status.normal THEN
                    dmp$file_on_down_volume (ijle_p^.swap_data.swap_file_sfid, file_on_down_volume);
                    IF file_on_down_volume THEN
                      IF NOT file_reassigned THEN
                        ijle_p^.swap_data.swapping_io_error := ioc$unrecovered_error_unit_down;
                      ELSE
                        EXIT /fix_swap_file/;
                      IFEND;
                    ELSE
                      pmp$delay (1000, local_status);
                    IFEND;
                  ELSE

{ The following call to device management is required to insure that EOI of the swap file is set.
{ This is only required for the situation where the job is swapped out and is not swapped in
{ again until we are attempting job recovery. This call can be removed when the procedure
{ DMP$FETCH_CHAPTER_INFO sets EOI of a file on a write instead of a read.

                    dmp$set_eoi (ijle_p^.swap_data.swap_file_sfid,
                      (total_swapped_page_count * osv$page_size), status);
                  IFEND;
                ELSE
                  CYCLE /search_for_job_2/;
                IFEND;

              = ioc$media_error, ioc$unrecovered_error =
                dmp$reallocate_file_space (ijle_p^.swap_data.swap_file_sfid, FALSE, status);
                IF NOT status.normal THEN
                  ijle_p^.swap_data.swapping_io_error := ioc$unrecovered_error_unit_down;
                IFEND;

              = ioc$unrecovered_error_unit_down =
                ijle_p^.swap_data.swap_file_length_in_pages := 0;
                log_message (jsc$mt_reassign_file, ijle_p);
                total_swapped_page_count := ijle_p^.swap_data.swapped_job_page_count +
                      ijle_p^.swap_data.swapped_job_entry.swap_file_descriptor_page_count;
                dmp$reassign_file (ijle_p^.swap_data.swap_file_sfid,
                      (total_swapped_page_count * osv$page_size), status);
                IF NOT status.normal THEN
                  IF status.condition = dme$io_active THEN
                    pmp$delay (1000, local_status);
                  ELSEIF status.condition = dme$unable_to_alloc_all_space THEN
                    file_reassigned := TRUE;
                    ijle_p^.swap_data.swapping_io_error := ioc$allocate_file_space;
                  ELSE
                    EXIT /fix_swap_file/;
                  IFEND;
                ELSE
                  dmp$set_eoi (ijle_p^.swap_data.swap_file_sfid,
                      (total_swapped_page_count * osv$page_size), status);
                  ijle_p^.swap_data.swap_file_length_in_pages := total_swapped_page_count;
                IFEND;

              ELSE
                CYCLE /search_for_job_2/;
              CASEND;
            ELSE
              CYCLE /search_for_job_2/;
            CASEND;
          UNTIL status.normal OR (fix_swap_file_pass = 10);

          IF NOT status.normal THEN
            log_message (jsc$mt_report_status, ijle_p);
            status.normal := TRUE;
          ELSE
            issue_monitor_request (ijl_ordinal, jsc$jss_advance_swap, status);
          IFEND;

        FOREND /search_for_job_2/;
      IFEND;
    FOREND /search_for_job_1/;

  PROCEND jsp$help_monitor_mode_swapper;

?? TITLE := '[XDCL] jsp$special_job_swapout', EJECT ??

{ PURPOSE:
{   This procedure issues the monitor request to process an operator swapout.

  PROCEDURE [XDCL] jsp$special_job_swapout
    (    ijl_ordinal: jmt$ijl_ordinal;
         reason: jmt$swapout_reasons;
     VAR status: ost$status);

    VAR
      request_block: jst$rb_job_swapping_functions;

    request_block.reqcode := syc$rc_job_swapping_functions;
    request_block.ijl_ordinal := ijl_ordinal;
    request_block.subfunction := jsc$jss_special_swapout;
    request_block.swapout_reason := reason;
    request_block.memory_needed := 0;

    i#call_monitor (#LOC (request_block), #SIZE (request_block));

    syp$set_status_from_mtr_status (request_block.status, status);

  PROCEND jsp$special_job_swapout;


?? TITLE := 'JSP$RESET_MAXIMUM_TIME' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] jsp$reset_maximum_time;

    VAR
      i: jmt$ijl_swap_status,
      j: jmt$ijl_swap_status;

    FOR i := LOWERBOUND (jsv$swap_state_statistics) TO UPPERBOUND (jsv$swap_state_statistics) DO
      FOR j := LOWERBOUND (jsv$swap_state_statistics) TO UPPERBOUND (jsv$swap_state_statistics) DO
        jsv$swap_state_statistics [i] [j].maximum_time := 0;
      FOREND;
    FOREND;

  PROCEND jsp$reset_maximum_time;
?? TITLE := 'JSP$SWAP_JOB_IN' ??
?? EJECT ??

  PROCEDURE [XDCL] jsp$swap_job_in
    (    ijl_ordinal: jmt$ijl_ordinal;
     VAR status: ost$status);

*copy jsh$swap_job_in


    issue_monitor_request (ijl_ordinal, jsc$jss_swap_job_in, status);

  PROCEND jsp$swap_job_in;

?? TITLE := '[XDCL] jsp$swap_job_out', EJECT ??

*copy jsh$swap_job_out

  PROCEDURE [XDCL] jsp$swap_job_out
    (    ijl_ordinal: jmt$ijl_ordinal;
         swapout_reason: jmt$swapout_reasons;
         memory_needed: mmt$page_frame_index;
     VAR status: ost$status);

    VAR
      request_block: jst$rb_job_swapping_functions;

    request_block.reqcode := syc$rc_job_swapping_functions;
    request_block.ijl_ordinal := ijl_ordinal;
    request_block.subfunction := jsc$jss_swap_job_out;
    request_block.swapout_reason := swapout_reason;
    request_block.memory_needed := memory_needed;

    i#call_monitor (#LOC (request_block), #SIZE (request_block));

    syp$set_status_from_mtr_status (request_block.status, status);

  PROCEND jsp$swap_job_out;
MODEND jsm$job_swapper;
