?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Job Management : Job Scheduler Monitor and Ring 3 Procedures' ??
MODULE jmm$job_scheduler_ring_3;


?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
*copyc jmv$ijl_p
*copyc jmv$jcb
*copyc jmv$job_class_table_p
*copyc jmv$job_counts
*copyc jmv$job_sched_events_selected
*copyc jmv$job_scheduler_event
*copyc jmv$job_scheduler_table
*copyc jmv$next_job_cand_refresh_time
*copyc jmv$sched_service_calc_time
*copyc jmv$system_job_ssn
*copyc jmv$time_to_wake_scheduler
*copyc mmv$resident_job_target

*copyc avp$system_operator
*copyc jmp$call_job_swapper
*copyc jmp$change_dispatching_prior_r1
*copyc jmp$clear_scheduler_event
*copyc jmp$get_job_ijl_ordinal
*copyc jmp$get_ijle_p
*copyc jmp$idling_swap_all_jobs
*copyc jmp$initialize_sched_ring_2
*copyc jmp$initialize_sched_variables
*copyc jmp$incr_scheduler_statistics
*copyc jmp$process_activate_job
*copyc jmp$process_change_dispatching
*copyc jmp$process_damaged_jobs
*copyc jmp$process_operator_requests
*copyc jmp$process_subsyst_prio_change
*copyc jmp$process_terminated_job
*copyc jmp$process_thrashing
*copyc jmp$queue_operator_request
*copyc jmp$recover_swapin_jobs
*copyc jmp$reset_time_to_wake_sched
*copyc jmp$scan_ajl_for_service
*copyc jmp$select_reset_disp_pr
*copyc jmp$set_examine_input_event
*copyc jmp$set_sched_service_calc_time
*copyc jmp$set_scheduler_time_event
*copyc jmp$swap_job_for_memory_reserve
*copyc jmp$swap_jobs_for_lower_maxaj
*copyc jmp$test_for_system_idle_r1
*copyc osp$generate_log_message
*copyc osp$recovery_swap_io_error
*copyc osp$set_status_abnormal
*copyc osp$verify_system_privilege
*copyc pmp$get_executing_task_gtid
*copyc pmp$wait
*copyc tmp$save_system_task_id
*copyc tmp$clear_wait_inhibited
*copyc tmp$set_task_priority

{?? PUSH(LISTEXT := ON) ??

*copyc clt$value
*copyc fst$path
*copyc jmc$class_names
*copyc jmc$special_dispatch_priorities
*copyc jme$job_scheduler_conditions
*copyc jme$queued_file_conditions
*copyc jmt$ajl_ordinal
*copyc jmt$dispatching_control_info
*copyc jmt$dispatching_priority
*copyc jmt$job_class_set
*copyc jmt$job_priority
*copyc jmt$job_scheduler_statistics
*copyc jmt$job_scheduler_table
*copyc jmt$service_class_set
*copyc jmt$system_supplied_name
*copyc ofe$error_codes
*copyc oss$task_shared
*copyc ost$global_task_id
*copyc ost$status
*copyc tmc$wait_times

{?? POP ??

?? TITLE := 'JMP$JOB_SCHEDULER_MONITOR', EJECT ??


  PROCEDURE [XDCL] jmp$job_scheduler_monitor;

{
{ PURPOSE:
{   To process job scheduler events.
{ DESIGN:
{   Scheduler processes all events that are set and selected.  When event processing is
{   completed, scheduler goes into a wait.  The next time an event is set, scheduler will
{   be readied.

    VAR
      wait_time: integer,
      was_set: boolean,
      local_status: ost$status,
      global_task_id: ost$global_task_id,
      processed_event_this_pass: boolean,
      processed_thrashing_this_pass: boolean;

    tmp$set_task_priority (jmc$priority_job_scheduler, 0, local_status);
    tmp$save_system_task_id (tmc$stid_job_scheduler, TRUE, local_status);

    jmp$initialize_sched_variables;
    jmp$initialize_sched_ring_2;
    jmp$reset_time_to_wake_sched;

{  we are now  done with initialization

    jmp$set_sched_service_calc_time;

    WHILE TRUE DO
      processed_thrashing_this_pass := FALSE;

      REPEAT

        processed_event_this_pass := FALSE;
        tmp$clear_wait_inhibited (was_set);

        IF jmv$job_scheduler_event [jmc$call_job_swapper] AND
              jmv$job_sched_events_selected [jmc$call_job_swapper] THEN
          processed_event_this_pass := TRUE;
          jmp$call_job_swapper;
        IFEND;

        IF jmv$job_scheduler_event [jmc$job_terminated] AND
              jmv$job_sched_events_selected [jmc$job_terminated] THEN
          processed_event_this_pass := TRUE;
          jmp$process_terminated_job;
        IFEND;

        IF jmv$job_scheduler_event [jmc$recovery_swap_io_error] AND
              jmv$job_sched_events_selected [jmc$recovery_swap_io_error] THEN
          jmp$incr_scheduler_statistics (jmc$recovery_swap_error);
          processed_event_this_pass := TRUE;
          jmp$process_recovery_swap_error;
        IFEND;

        IF jmv$job_scheduler_event [jmc$recovery_job_damaged] AND
              jmv$job_sched_events_selected [jmc$recovery_job_damaged] THEN
          processed_event_this_pass := TRUE;
          jmp$process_damaged_jobs;
        IFEND;

        IF (#FREE_RUNNING_CLOCK (0)) >= jmv$sched_service_calc_time THEN
          jmp$scan_ajl_for_service;
          jmp$set_sched_service_calc_time;
        IFEND;

        IF jmv$job_scheduler_event [jmc$system_is_idling] AND
              jmv$job_sched_events_selected [jmc$system_is_idling] THEN
          jmp$incr_scheduler_statistics (jmc$idle_system_event_count);
          jmp$idling_swap_all_jobs;
        IFEND;

        IF jmv$job_scheduler_event [jmc$recovery_swapin] AND
              jmv$job_sched_events_selected [jmc$recovery_swapin] THEN
          jmp$recover_swapin_jobs;
        IFEND;

        IF jmv$job_scheduler_event [jmc$swap_jobs_for_lower_maxaj] AND
              jmv$job_sched_events_selected [jmc$swap_jobs_for_lower_maxaj] THEN
          jmp$incr_scheduler_statistics (jmc$lower_maxaj_event_count);
          jmp$swap_jobs_for_lower_maxaj;
        IFEND;

        IF jmv$job_scheduler_event [jmc$change_dispatching_controls] AND
              jmv$job_sched_events_selected [jmc$change_dispatching_controls] THEN
          jmp$process_change_dispatching;
        IFEND;

        IF jmv$job_scheduler_event [jmc$subsystem_priority_change] AND
              jmv$job_sched_events_selected [jmc$subsystem_priority_change] THEN
          jmp$process_subsyst_prio_change;
        IFEND;

        IF jmv$job_scheduler_event [jmc$swap_job_for_memory_reserve] AND
              jmv$job_sched_events_selected [jmc$swap_job_for_memory_reserve] THEN
          jmp$incr_scheduler_statistics (jmc$memory_reserve_event_count);
          jmp$swap_job_for_memory_reserve;
        IFEND;

        IF jmv$job_scheduler_event [jmc$system_is_thrashing] AND
              jmv$job_sched_events_selected [jmc$system_is_thrashing] THEN
          jmp$incr_scheduler_statistics (jmc$system_thrashing_event_cnt);
          processed_event_this_pass := TRUE;
          jmp$process_thrashing;
          processed_thrashing_this_pass := TRUE;
        IFEND;

        IF jmv$job_scheduler_event [jmc$process_operator_request] AND
              jmv$job_sched_events_selected [jmc$process_operator_request] THEN
          jmp$incr_scheduler_statistics (jmc$operator_request_event_cnt);
          processed_event_this_pass := TRUE;

          jmp$clear_scheduler_event (jmc$process_operator_request);

          REPEAT
            jmp$process_operator_requests (local_status);

            IF NOT local_status.normal THEN
              osp$generate_log_message ($pmt$ascii_logset [pmc$system_log], local_status, local_status);
              local_status.normal := FALSE;
            IFEND;

          UNTIL local_status.normal


        IFEND;

        IF #FREE_RUNNING_CLOCK (0) >= jmv$next_job_cand_refresh_time THEN
          jmp$set_examine_input_event;
        IFEND;

        IF (NOT processed_thrashing_this_pass) AND ((jmv$job_scheduler_event [jmc$examine_input_queue] AND
              jmv$job_sched_events_selected [jmc$examine_input_queue]) OR
              (jmv$job_scheduler_event [jmc$examine_swapin_queue] AND
              jmv$job_sched_events_selected [jmc$examine_swapin_queue]) OR
              (jmv$job_scheduler_event [jmc$scheduler_wake_time] AND
              jmv$job_sched_events_selected [jmc$scheduler_wake_time]) OR
              (jmv$job_scheduler_event [jmc$needed_memory_available] AND
              jmv$job_sched_events_selected [jmc$needed_memory_available]) OR
              (jmv$job_scheduler_event [jmc$needed_ajlo_available] AND
              jmv$job_sched_events_selected [jmc$needed_ajlo_available])) THEN
          jmp$incr_scheduler_statistics (jmc$activate_event_count);
          processed_event_this_pass := TRUE;
          jmp$process_activate_job;
        IFEND;

      UNTIL NOT processed_event_this_pass;

      IF jmv$next_job_cand_refresh_time < jmv$time_to_wake_scheduler THEN
        wait_time := (jmv$next_job_cand_refresh_time - #FREE_RUNNING_CLOCK (0)) DIV 1000;
      ELSE
        wait_time := (jmv$time_to_wake_scheduler - #FREE_RUNNING_CLOCK (0)) DIV 1000;
      IFEND;
      IF wait_time > 500 THEN
        jmp$incr_scheduler_statistics (jmc$long_wait);
      ELSE
        jmp$incr_scheduler_statistics (jmc$short_wait);
      IFEND;

      IF wait_time > 0 THEN
        pmp$wait (wait_time, wait_time);
        IF jmv$time_to_wake_scheduler < #FREE_RUNNING_CLOCK (0) THEN
          jmp$set_scheduler_time_event;
        IFEND;
      ELSE
        IF jmv$job_sched_events_selected [jmc$scheduler_wake_time] THEN
          jmp$set_scheduler_time_event;
        ELSE {system is idle--reset wake time to wake scheduler in the future
          jmp$reset_time_to_wake_sched;
        IFEND;
      IFEND;

    WHILEND;
  PROCEND jmp$job_scheduler_monitor;

?? TITLE := 'jmp$process_recovery_swap_error', EJECT ??

  PROCEDURE jmp$process_recovery_swap_error;

    jmp$clear_scheduler_event (jmc$recovery_swap_io_error);
    osp$recovery_swap_io_error;

  PROCEND jmp$process_recovery_swap_error;

?? TITLE := '[XDCL, #GATE] jmp$reset_dispatching_priority', EJECT ??

{ PURPOSE:
{   To reset the dispatching control information for interactive jobs.
{ DESIGN:
{   This procedure is called when command processing gets input from an interactive terminal.

  PROCEDURE [XDCL, #GATE] jmp$reset_dispatching_priority;

    VAR
      null_dispatching_info: jmt$dispatching_control_info,
      status: ost$status;

    status.normal := TRUE;
    IF jmv$jcb.system_name = jmv$system_job_ssn THEN
      RETURN;
    IFEND;
    jmp$change_dispatching_prior_r1 (tmc$cpo_interactive_command, jmv$jcb.ijl_ordinal, jmv$jcb.system_name,
          null_dispatching_info, status);

  PROCEND jmp$reset_dispatching_priority;
?? TITLE := '[XDCL] jmp$restore_dispatching_control', EJECT ??

{ PURPOSE:
{   To restore a job's dispatching control information.
{ DESIGN:
{   This procedure is called after a user interrupt to restore the dispatching control
{   information a job was exeuting with at the time the interrupt occurred.

  PROCEDURE [XDCL] jmp$restore_dispatching_control
    (    dispatching_control_info: jmt$dispatching_control_info);

    VAR
      status: ost$status;

    status.normal := TRUE;
    IF jmv$jcb.system_name = jmv$system_job_ssn THEN
      RETURN;
    IFEND;
    jmp$change_dispatching_prior_r1 (tmc$cpo_interrupt_restore, jmv$jcb.ijl_ordinal, jmv$jcb.system_name,
          dispatching_control_info, status);

  PROCEND jmp$restore_dispatching_control;

?? OLDTITLE, NEWTITLE := '[XDCL, #GATE]  JMP$SELECT_RESET_DISP_PR_R3', EJECT ??
*copy jmh$select_reset_disp_pr_r3

  PROCEDURE [XDCL, #GATE] jmp$select_reset_disp_pr_r3;

    jmp$select_reset_disp_pr;
  PROCEND jmp$select_reset_disp_pr_r3;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] jmp$swapout_job', EJECT ??
*copy jmh$swapout_job

{ PURPOSE:
{   This procedure is the ring 3 code for the operator SWAPOUT command.
{ DESIGN:
{   The swapout request must be queued for the job scheduler to process (the swapout
{   must be synchronized by scheduler).

  PROCEDURE [XDCL, #GATE] jmp$swapout_job
    (    job_name: ost$name;
         disable_recovery: boolean;
     VAR status: ost$status);

    VAR
      ijl_ordinal: jmt$ijl_ordinal,
      privileged_job: boolean,
      system_supplied_name: jmt$system_supplied_name;

    privileged_job := avp$system_operator ();
    IF NOT privileged_job THEN
      osp$set_status_abnormal ('OF', ofe$sou_not_active, 'system_operator', status);
      RETURN;
    IFEND;

    jmp$get_job_ijl_ordinal (job_name, privileged_job, ijl_ordinal, system_supplied_name, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    jmp$queue_operator_request (jmc$or_swapout, ijl_ordinal, system_supplied_name,
          jmc$null_dispatching_priority, disable_recovery, status);

  PROCEND jmp$swapout_job;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] jmp$swapin_job', EJECT ??
*copy jmh$swapin_job

{ PURPOSE:
{   This procedure is the ring 3 code for the operator SWAPIN command.
{ DESIGN:
{   The swapin request must be queued for the job scheduler to process (the swapin
{   must be synchronized by scheduler).

  PROCEDURE [XDCL, #GATE] jmp$swapin_job
    (    job_name: clt$value;
     VAR status: ost$status);

    VAR
      ijle_p: ^jmt$initiated_job_list_entry,
      ijl_ordinal: jmt$ijl_ordinal,
      privileged_job: boolean,
      system_supplied_name: jmt$system_supplied_name;

    privileged_job := avp$system_operator ();
    IF NOT privileged_job THEN
      osp$set_status_abnormal ('OF', ofe$sou_not_active, 'system_operator', status);
      RETURN;
    IFEND;

    jmp$get_job_ijl_ordinal (job_name.name.value, privileged_job, ijl_ordinal, system_supplied_name, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    jmp$get_ijle_p (ijl_ordinal, ijle_p);
    IF ijle_p^.entry_status = jmc$ies_job_damaged THEN
      osp$set_status_abnormal ('JM', jme$job_damaged_during_recovery, job_name.name.value, status);
      RETURN;
    IFEND;

    jmp$queue_operator_request (jmc$or_swapin, ijl_ordinal, system_supplied_name,
          jmc$null_dispatching_priority, {disable_recovery} FALSE, status);

  PROCEND jmp$swapin_job;
?? TITLE := 'JMP$TEST_FOR_SYSTEM_IDLE', EJECT ??

  PROCEDURE [XDCL, #GATE] jmp$test_for_system_idle
    (VAR status: ost$status);

    status.normal := TRUE;
    jmp$test_for_system_idle_r1 (status);

  PROCEND jmp$test_for_system_idle;
MODEND jmm$job_scheduler_ring_3;
