?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE : Job Leveler Management Ring 1' ??
MODULE qfm$queue_file_leveler_manager;

{ PURPOSE:
{   This module contains the interfaces responsible for the manipulation of the
{   Known Job List (KJL) for the job leveler task.
{
{ DESIGN:
{   The procedures in this module reference the Known Job List (KJL) and execute
{   in ring one.  The procedures in this module are callable from ring 3 and are
{   used solely for the purposes of leveling jobs across mainframes.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc jmc$input_queue_full_message
*copyc jmc$job_management_id
*copyc jme$queued_file_conditions
*copyc jmt$clock_time
*copyc jmt$jl_assigned_job_list
*copyc jmt$jl_job_class_data
*copyc jmt$jl_job_class_priorities
*copyc jmt$jl_missing_job_list
*copyc jmt$jl_server_job_end_info
*copyc jmt$jl_server_job_list
*copyc jmt$jl_server_job_priorities
*copyc jmt$jl_unassigned_job_list
*copyc jmt$job_category_set
*copyc jmt$job_count_range
*copyc osd$integer_limits
*copyc oss$mainframe_pageable
*copyc oss$mainframe_paged_literal
*copyc ost$status
*copyc pmt$binary_mainframe_id
?? POP ??
*copyc dpp$put_critical_message
*copyc jmp$force_candidate_refresh
*copyc jmp$notify_job_scheduler_of_job
*copyc osp$clear_mainframe_sig_lock
*copyc osp$set_mainframe_sig_lock
*copyc osp$set_status_condition
*copyc osp$system_error
*copyc pmp$delay
*copyc pmp$get_executing_task_gtid
*copyc qfp$expand_kjl
*copyc qfp$get_profile_mainframe_index
*copyc qfp$job_selection_priority
*copyc qfp$relink_kjl_application
*copyc qfp$relink_kjl_client
*copyc qfp$relink_kjl_entry
*copyc qfp$relink_kjl_server
*copyc jmv$candidate_queued_jobs
*copyc jmv$job_class_table_p
*copyc jmv$job_counts
*copyc jmv$job_scheduler_table
*copyc jmv$kjl_p
*copyc jmv$kjlx_p
*copyc jmv$known_job_list
*copyc jmv$leveler_profile_loading
*copyc jmv$maximum_job_class_in_use
*copyc jmv$maximum_known_jobs
*copyc jmv$maximum_profile_index
*copyc jmv$profile_index_to_job_class
*copyc qfv$current_kjl_limit
*copyc qfv$kjl_lock
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??

  VAR
    null_binary_mainframe_id: [STATIC, READ, oss$mainframe_paged_literal] pmt$binary_mainframe_id := [0, 0],
    qfv$leveler_readied: [STATIC, XDCL, #GATE, oss$mainframe_pageable] boolean := FALSE;

?? OLDTITLE ??
?? NEWTITLE := 'determine_server_kjl_index', EJECT ??

{ PURPOSE:
{   This request will find the server KJL index for a job assigned to a client.
{
{ NOTES:
{   The Known Job List (KJL) must be locked when this request is issued.
{   A server_kjl_index of jmc$kjl_undefined_index will be returned if the
{   job was not found.

  PROCEDURE determine_server_kjl_index
    (    kjl_client_index: jmt$kjl_client_index;
         system_job_name: jmt$system_supplied_name;
         probable_server_kjl_index: jmt$kjl_index;
     VAR server_kjl_index: jmt$kjl_index);

    VAR
      kjl_index: jmt$kjl_index;

    IF (probable_server_kjl_index <> jmc$kjl_undefined_index) AND
          (probable_server_kjl_index <= UPPERBOUND (jmv$kjl_p^)) THEN
      IF jmv$kjl_p^ [probable_server_kjl_index].system_job_name = system_job_name THEN
        server_kjl_index := probable_server_kjl_index;
        RETURN;
      IFEND;
    IFEND;
    kjl_index := jmv$known_job_list.client_data.state_data [kjl_client_index].first_entry;
    WHILE (kjl_index <> jmc$kjl_undefined_index) AND (jmv$kjl_p^ [kjl_index].system_job_name <>
          system_job_name) DO
      kjl_index := jmv$kjl_p^ [kjl_index].client_forward_link;
    WHILEND;
    server_kjl_index := kjl_index;
  PROCEND determine_server_kjl_index;
?? OLDTITLE ??
?? NEWTITLE := 'find_client_mainframe_id', EJECT ??

{ PURPOSE:
{   This request searches the Known Job List Client Table for the specified mainframe
{   identifier.
{
{ DESIGN:
{   If the mainframe identifier is found return the kjl client index.  If the mainframe
{   identifier is not found then if add_if_not_found is true, add the indicated
{   mainframe identifier to the kjl client list and return the assigned kjl client
{   index.  If add_if_not_found is false or the client list is full set
{   client_mainframe_id_in_kjl to false.
{
{ NOTES:
{   The Known Job List (KJL) must be locked when this request is issued.

  PROCEDURE find_client_mainframe_id
    (    client_mainframe_id: pmt$binary_mainframe_id;
         add_if_not_found: boolean;
     VAR client_mainframe_id_in_kjl: boolean;
     VAR kjl_client_index: jmt$kjl_client_index);

    VAR
      local_kjl_client_index: jmt$kjl_client_index;

    client_mainframe_id_in_kjl := FALSE;

  /search_for_mainframe_id/
    FOR local_kjl_client_index := jmc$kjl_client_this_mainframe TO UPPERVALUE (jmt$kjl_client_index) DO
      IF jmv$known_job_list.client_data.state_data [local_kjl_client_index].mainframe_id =
            client_mainframe_id THEN
        client_mainframe_id_in_kjl := TRUE;
        kjl_client_index := local_kjl_client_index;
        EXIT /search_for_mainframe_id/;
      IFEND;
    FOREND /search_for_mainframe_id/;
    IF (NOT client_mainframe_id_in_kjl) AND add_if_not_found THEN

    /search_for_empty_client_entry/
      FOR local_kjl_client_index := jmc$kjl_client_this_mainframe + 1 TO UPPERVALUE (jmt$kjl_client_index) DO
        IF jmv$known_job_list.client_data.state_data [local_kjl_client_index].mainframe_id =
              null_binary_mainframe_id THEN
          jmv$known_job_list.client_data.state_data [local_kjl_client_index].mainframe_id :=
                client_mainframe_id;
          client_mainframe_id_in_kjl := TRUE;
          kjl_client_index := local_kjl_client_index;
          EXIT /search_for_empty_client_entry/;
        IFEND;
      FOREND /search_for_empty_client_entry/;
    IFEND;
  PROCEND find_client_mainframe_id;
?? OLDTITLE ??
?? NEWTITLE := 'find_server_mainframe_id', EJECT ??

{ PURPOSE:
{   This request searches the Known Job List Server Table for the specified mainframe
{   identifier.
{
{ DESIGN:
{   If the mainframe identifier is found return the kjl server index.  If the mainframe
{   identifier is not found then if add_if_not_found is true, add the indicated
{   mainframe identifier to the kjl server list and return the assign kjl server
{   index.  If add_if_not_found is false or the server list is full set
{   server_mainframe_id_in_kjl to false.
{
{ NOTES:
{   The Known Job List (KJL) must be locked when this request is issued.

  PROCEDURE find_server_mainframe_id
    (    server_mainframe_id: pmt$binary_mainframe_id;
         add_if_not_found: boolean;
     VAR server_mainframe_id_in_kjl: boolean;
     VAR kjl_server_index: jmt$kjl_server_index);

    VAR
      local_kjl_server_index: jmt$kjl_server_index;

    server_mainframe_id_in_kjl := FALSE;

  /search_for_mainframe_id/
    FOR local_kjl_server_index := jmc$kjl_server_this_mainframe TO UPPERVALUE (jmt$kjl_server_index) DO
      IF jmv$known_job_list.server_data.state_data [local_kjl_server_index].mainframe_id =
            server_mainframe_id THEN
        server_mainframe_id_in_kjl := TRUE;
        kjl_server_index := local_kjl_server_index;
        EXIT /search_for_mainframe_id/;
      IFEND;
    FOREND /search_for_mainframe_id/;
    IF (NOT server_mainframe_id_in_kjl) AND add_if_not_found THEN

    /search_for_empty_server_entry/
      FOR local_kjl_server_index := jmc$kjl_server_this_mainframe + 1 TO UPPERVALUE (jmt$kjl_server_index) DO
        IF jmv$known_job_list.server_data.state_data [local_kjl_server_index].mainframe_id =
              null_binary_mainframe_id THEN
          jmv$known_job_list.server_data.state_data [local_kjl_server_index].mainframe_id :=
                server_mainframe_id;
          server_mainframe_id_in_kjl := TRUE;
          kjl_server_index := local_kjl_server_index;
          EXIT /search_for_empty_server_entry/;
        IFEND;
      FOREND /search_for_empty_server_entry/;
    IFEND;
  PROCEND find_server_mainframe_id;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] qfp$assign_jobs_to_client', EJECT ??
*copy qfh$assign_jobs_to_client

  PROCEDURE [XDCL, #GATE] qfp$assign_jobs_to_client
    (    client_mainframe_id: pmt$binary_mainframe_id;
         leveler_job_class_data: jmt$jl_job_class_data;
         job_class_priorities: jmt$jl_job_class_priorities;
         initiation_required_categories: jmt$job_category_set;
         initiation_excluded_categories: jmt$job_category_set;
         assigned_job_list_p { output } : ^jmt$jl_assigned_job_list;
     VAR number_of_jobs_assigned: jmt$job_count_range;
     VAR server_job_priorities: jmt$jl_server_job_priorities);

    VAR
      assigned_job_list_size: jmt$job_count_range,
      client_in_kjl: boolean,
      current_clock_time: jmt$clock_time,
      eligible_job_categories: boolean,
      job_assignable_to_client: boolean,
      job_class: jmt$job_class,
      job_class_assigned_job_count: jmt$job_count_range,
      job_priority: jmt$job_priority,
      kjl_client_index: jmt$kjl_client_index,
      kjl_index: jmt$kjl_index,
      mainframe_index: jmt$maximum_mainframes,
      next_kjl_index: jmt$kjl_index,
      number_of_jobs_needed_for_class: ost$non_negative_integers,
      profile_job_class: jmt$job_class,
      required_job_priority: jmt$job_priority;

    number_of_jobs_assigned := 0;
    current_clock_time := #FREE_RUNNING_CLOCK (0);
    assigned_job_list_size := UPPERBOUND (assigned_job_list_p^);

    osp$set_mainframe_sig_lock (qfv$kjl_lock);
    find_client_mainframe_id (client_mainframe_id, { add_if_not_found } TRUE, client_in_kjl,
          kjl_client_index);
    IF client_in_kjl THEN

{ Determine the mainframe index of the client mainframe.  In order to request jobs
{ from the server, the client, by definition, must be in the active profile so a
{ valid mainframe is always returned.

      qfp$get_profile_mainframe_index (client_mainframe_id, mainframe_index);

      FOR profile_job_class := 1 TO jmv$maximum_profile_index DO
        job_class := jmv$profile_index_to_job_class [profile_job_class];
        server_job_priorities [profile_job_class] := 0;
        IF (job_class <= jmv$maximum_job_class_in_use) AND (job_class >= jmc$system_job_class) THEN
          number_of_jobs_needed_for_class := leveler_job_class_data [profile_job_class].termination_count +
                leveler_job_class_data [profile_job_class].room_in_class;
          IF number_of_jobs_needed_for_class > (UPPERVALUE (number_of_jobs_assigned) -
                number_of_jobs_assigned) THEN
            number_of_jobs_needed_for_class := UPPERVALUE (number_of_jobs_assigned) - number_of_jobs_assigned;
          IFEND;
          job_class_assigned_job_count := 0;
          kjl_index := jmv$known_job_list.queued_class_entries [job_class].first_queued_class_entry;

        /assign_jobs_to_client/
          WHILE kjl_index <> jmc$kjl_undefined_index DO

{ A job is assignable if and only if all the following are true:
{ o The job's categories fit the initiation required/excluded categories from the client.
{ o The client's mainframe index is in the valid_mainframe_set for the job.
{ o The job is not already assigned to a client.
{ o The job's server mainframe is the mainframe on which this request executes.
{ o The job does not have a Job_Destination_Usage of VE_LOCAL.
{ o The job has sufficient priority to be assigned to the client.
{ o The job is a batch job.

            next_kjl_index := jmv$kjl_p^ [kjl_index].class_forward_link;
            eligible_job_categories := ((initiation_required_categories *
                  jmv$kjl_p^ [kjl_index].job_category_set) = initiation_required_categories) AND
                  ((initiation_excluded_categories * jmv$kjl_p^ [kjl_index].job_category_set) =
                  $jmt$job_category_set []);

            job_assignable_to_client := eligible_job_categories AND
                  (mainframe_index IN jmv$kjlx_p^ [kjl_index].valid_mainframe_set) AND
                  (jmv$kjlx_p^ [kjl_index].job_mode = jmc$batch) AND
                  (jmv$kjl_p^ [kjl_index].client_index = jmc$kjl_client_undefined) AND
                  (jmv$kjl_p^ [kjl_index].destination_usage <> jmc$ve_local_usage) AND
                  (jmv$kjl_p^ [kjl_index].server_index = jmc$kjl_server_this_mainframe);

            IF job_assignable_to_client THEN
              job_priority := qfp$job_selection_priority (current_clock_time, kjl_index);
              IF (job_class_priorities [profile_job_class].job_priority +
                    jmv$job_scheduler_table.job_leveling_priority_bias +
                    jmv$job_class_table_p^ [job_class].job_leveling_priority_bias) < 0 THEN
                required_job_priority := 0;
              ELSEIF (job_class_priorities [profile_job_class].job_priority +
                    jmv$job_scheduler_table.job_leveling_priority_bias +
                    jmv$job_class_table_p^ [job_class].job_leveling_priority_bias) >
                    UPPERVALUE (jmt$job_priority) THEN
                required_job_priority := UPPERVALUE (jmt$job_priority);
              ELSE
                required_job_priority := (job_class_priorities [profile_job_class].job_priority +
                      jmv$job_scheduler_table.job_leveling_priority_bias +
                      jmv$job_class_table_p^ [job_class].job_leveling_priority_bias);
              IFEND;

{ Treat a full assigned job list the same as if the maximum number of jobs had been
{ assigned to the client for the job class.  If a profile is loading, only return the
{ priority of the highest assignable job.

              IF (job_class_assigned_job_count < number_of_jobs_needed_for_class) AND
                    (number_of_jobs_assigned < assigned_job_list_size) AND
                    ((job_priority > required_job_priority) OR ((job_priority = required_job_priority) AND
                    job_class_priorities [profile_job_class].based_on_selection_priority)) AND
                    (NOT jmv$leveler_profile_loading) THEN
                number_of_jobs_assigned := number_of_jobs_assigned + 1;
                job_class_assigned_job_count := job_class_assigned_job_count + 1;
                assigned_job_list_p^ [number_of_jobs_assigned].system_job_name :=
                      jmv$kjl_p^ [kjl_index].system_job_name;
                assigned_job_list_p^ [number_of_jobs_assigned].user_job_name :=
                      jmv$kjl_p^ [kjl_index].user_job_name;
                assigned_job_list_p^ [number_of_jobs_assigned].login_user_identification :=
                      jmv$kjlx_p^ [kjl_index].login_user_identification;
                assigned_job_list_p^ [number_of_jobs_assigned].control_user_identification :=
                      jmv$kjlx_p^ [kjl_index].job_controller;
                assigned_job_list_p^ [number_of_jobs_assigned].originating_ssn :=
                      jmv$kjlx_p^ [kjl_index].originating_ssn;

{ Save the job_submission_time and latest_clock_time as an increment of the number of
{ microseconds that must pass before the job has reached its latest_run_time.  This value
{ will be adjusted with the clock value of the client when the job is placed in the
{ KJL on the client mainframe.

                assigned_job_list_p^ [number_of_jobs_assigned].job_submission_time :=
                      jmv$kjl_p^ [kjl_index].job_submission_time - #FREE_RUNNING_CLOCK (0);
                assigned_job_list_p^ [number_of_jobs_assigned].latest_clock_time_to_initiate :=
                      jmv$kjlx_p^ [kjl_index].latest_clock_time_to_initiate - #FREE_RUNNING_CLOCK (0);

{ The job class value returned must be the profile job class index rather than the
{ memory (job class table) index.

                assigned_job_list_p^ [number_of_jobs_assigned].job_class := profile_job_class;
                assigned_job_list_p^ [number_of_jobs_assigned].job_category_set :=
                      jmv$kjl_p^ [kjl_index].job_category_set;
                assigned_job_list_p^ [number_of_jobs_assigned].output_disposition_key :=
                      jmv$kjlx_p^ [kjl_index].output_disposition_key;
                assigned_job_list_p^ [number_of_jobs_assigned].server_kjl_index := kjl_index;
                qfp$relink_kjl_client (kjl_index, kjl_client_index);
                qfp$relink_kjl_application (kjl_index, jmc$ve_input_application_index,
                      jmc$kjl_application_acquired);
                qfp$relink_kjl_entry (kjl_index, job_class, jmc$kjl_assigned_entry);

              ELSE
                server_job_priorities [job_class] := job_priority;
                EXIT /assign_jobs_to_client/;
              IFEND;
            IFEND;
            kjl_index := next_kjl_index;
          WHILEND /assign_jobs_to_client/;
        IFEND;
      FOREND;
    ELSE

{ The KJL client table is full.  No jobs can be assigned by this server to the requesting client.

      FOR job_class := LOWERVALUE (jmt$job_class) TO UPPERVALUE (jmt$job_class) DO
        server_job_priorities [job_class] := 0;
      FOREND;
    IFEND;
    osp$clear_mainframe_sig_lock (qfv$kjl_lock);
  PROCEND qfp$assign_jobs_to_client;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] qfp$assign_server_jobs', EJECT ??
*copy qfh$assign_server_jobs

{
{ NOTES:
{   This request cannot be executing while a profile is loading.  Before a profile is loaded
{ the job leveler task must be in sync and is not capable of requesting jobs for assignment.

  PROCEDURE [XDCL, #GATE] qfp$assign_server_jobs
    (    server_mainframe_id: pmt$binary_mainframe_id;
         assigned_job_list_p: ^jmt$jl_assigned_job_list;
     VAR number_of_jobs_assigned: jmt$job_count_range;
     VAR status: ost$status);

    VAR
      ignore_status_p: ^ost$status,
      kjl_index: jmt$kjl_index,
      kjl_server_index: jmt$kjl_server_index,
      server_in_kjl: boolean;

    status.normal := TRUE;
    number_of_jobs_assigned := 0;
    osp$set_mainframe_sig_lock (qfv$kjl_lock);

    find_server_mainframe_id (server_mainframe_id, { add_if_not_found } TRUE, server_in_kjl,
          kjl_server_index);

    IF assigned_job_list_p <> NIL THEN

    /assign_jobs_to_server/
      WHILE number_of_jobs_assigned < UPPERBOUND (assigned_job_list_p^) DO

        IF (jmv$known_job_list.state_data [jmc$kjl_unused_entry].first_entry = jmc$kjl_undefined_index) THEN
          qfp$expand_kjl;
        IFEND;

{ If the KJL is full, the server does not fit in the KJL or a profile is loading then
{ the jobs cannot be assigned.

        IF (qfv$current_kjl_limit - jmv$known_job_list.state_data [jmc$kjl_unused_entry].number_of_entries >=
              jmv$maximum_known_jobs) OR (NOT server_in_kjl) OR (jmv$leveler_profile_loading) THEN
          osp$set_status_condition (jme$maximum_jobs, status);
          PUSH ignore_status_p;
          dpp$put_critical_message (jmc$input_queue_full_message, ignore_status_p^);
          EXIT /assign_jobs_to_server/;
        ELSE
          number_of_jobs_assigned := number_of_jobs_assigned + 1;
          kjl_index := jmv$known_job_list.state_data [jmc$kjl_unused_entry].first_entry;

          jmv$kjl_p^ [kjl_index].system_job_name := assigned_job_list_p^ [number_of_jobs_assigned].
                system_job_name;
          jmv$kjl_p^ [kjl_index].user_job_name := assigned_job_list_p^ [number_of_jobs_assigned].
                user_job_name;
          jmv$kjl_p^ [kjl_index].initiated_job_list_ordinal.block_number := LOWERVALUE (jmt$ijl_block_number);
          jmv$kjl_p^ [kjl_index].initiated_job_list_ordinal.block_index := LOWERVALUE (jmt$ijl_block_index);
          jmv$kjl_p^ [kjl_index].job_submission_time := assigned_job_list_p^ [number_of_jobs_assigned].
                job_submission_time + #FREE_RUNNING_CLOCK (0);
          jmv$kjl_p^ [kjl_index].earliest_clock_time_to_initiate := jmc$earliest_clock_time;

{ The assigned job list contains the profile index for the job class - not the
{ memory (job class table) index.

          jmv$kjl_p^ [kjl_index].job_class := jmv$profile_index_to_job_class
                [assigned_job_list_p^ [number_of_jobs_assigned].job_class];
          jmv$kjl_p^ [kjl_index].job_category_set := assigned_job_list_p^ [number_of_jobs_assigned].
                job_category_set;
          jmv$kjl_p^ [kjl_index].job_priority := qfp$job_selection_priority
                (#FREE_RUNNING_CLOCK (0), kjl_index);
          jmv$kjl_p^ [kjl_index].job_deferred_by_operator := FALSE;
          jmv$kjl_p^ [kjl_index].job_deferred_by_user := FALSE;
          jmv$kjl_p^ [kjl_index].login_family_available := TRUE;
          jmv$kjl_p^ [kjl_index].destination_usage := jmc$ve_usage;
          jmv$kjl_p^ [kjl_index].next_destination_usage := jmc$ve_usage;
          jmv$kjl_p^ [kjl_index].application_state := jmc$kjl_application_unused;
          jmv$kjl_p^ [kjl_index].application_forward_link := jmc$kjl_undefined_index;
          jmv$kjl_p^ [kjl_index].application_reverse_link := jmc$kjl_undefined_index;
          jmv$kjl_p^ [kjl_index].class_forward_link := jmc$kjl_undefined_index;
          jmv$kjl_p^ [kjl_index].class_reverse_link := jmc$kjl_undefined_index;
          jmv$kjl_p^ [kjl_index].client_index := jmc$kjl_client_undefined;
          jmv$kjl_p^ [kjl_index].client_forward_link := jmc$kjl_undefined_index;
          jmv$kjl_p^ [kjl_index].client_reverse_link := jmc$kjl_undefined_index;
          jmv$kjl_p^ [kjl_index].server_index := jmc$kjl_server_undefined;
          jmv$kjl_p^ [kjl_index].server_forward_link := jmc$kjl_undefined_index;
          jmv$kjl_p^ [kjl_index].server_reverse_link := jmc$kjl_undefined_index;
          jmv$kjl_p^ [kjl_index].server_kjl_index := assigned_job_list_p^ [number_of_jobs_assigned].
                server_kjl_index;

          jmv$kjlx_p^ [kjl_index].login_user_identification :=
                assigned_job_list_p^ [number_of_jobs_assigned].login_user_identification;
          jmv$kjlx_p^ [kjl_index].job_controller := assigned_job_list_p^ [number_of_jobs_assigned].
                control_user_identification;
          jmv$kjlx_p^ [kjl_index].originating_ssn := assigned_job_list_p^ [number_of_jobs_assigned].
                originating_ssn;
          jmv$kjlx_p^ [kjl_index].latest_clock_time_to_initiate :=
                assigned_job_list_p^ [number_of_jobs_assigned].latest_clock_time_to_initiate +
                #FREE_RUNNING_CLOCK (0);
          IF jmv$kjlx_p^ [kjl_index].latest_clock_time_to_initiate < jmc$earliest_clock_time THEN
            jmv$kjlx_p^ [kjl_index].latest_clock_time_to_initiate := jmc$earliest_clock_time;
          IFEND;
          jmv$kjlx_p^ [kjl_index].job_mode := jmc$batch;

{ The job monitor global task id is not set here - the job scheduler will set it when the job initiates.

          jmv$kjlx_p^ [kjl_index].output_disposition_key := assigned_job_list_p^ [number_of_jobs_assigned].
                output_disposition_key;
          jmv$kjlx_p^ [kjl_index].input_file_location := jmc$ifl_login_family_queue;
          jmv$kjlx_p^ [kjl_index].valid_mainframe_set := $jmt$valid_mainframe_set
                [jmc$kjl_server_this_mainframe];
          jmv$kjlx_p^ [kjl_index].timesharing_job := FALSE;
          jmv$kjlx_p^ [kjl_index].restart_job := FALSE;
          jmv$kjlx_p^ [kjl_index].system_label_p := NIL;
          jmv$kjlx_p^ [kjl_index].terminal_name := '';

          qfp$relink_kjl_entry (kjl_index, jmv$kjl_p^ [kjl_index].job_class, jmc$kjl_queued_entry);
          qfp$relink_kjl_application (kjl_index, jmc$ve_input_application_index, jmc$kjl_application_new);
          qfp$relink_kjl_server (kjl_index, kjl_server_index);
          jmp$notify_job_scheduler_of_job (jmv$kjl_p^ [kjl_index].job_class, kjl_index);
        IFEND;
      WHILEND /assign_jobs_to_server/;
    IFEND;
    osp$clear_mainframe_sig_lock (qfv$kjl_lock);
  PROCEND qfp$assign_server_jobs;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] qfp$clear_server_job_classes', EJECT ??
*copy qfh$clear_server_job_classes

  PROCEDURE [XDCL, #GATE] qfp$clear_server_job_classes;

    VAR
      job_class: jmt$job_class;

    osp$set_mainframe_sig_lock (qfv$kjl_lock);
    FOR job_class := jmc$system_job_class TO jmv$maximum_job_class_in_use DO
      jmv$known_job_list.queued_class_entries [job_class].termination_count := 0;
      jmv$known_job_list.queued_class_entries [job_class].number_of_jobs_needed := 0;
      jmv$known_job_list.queued_class_entries [job_class].server_mainframe_priority := 0;
      IF jmv$known_job_list.queued_class_entries [job_class].class_blocked_for_initiation THEN
        jmv$known_job_list.queued_class_entries [job_class].class_blocked_for_initiation := FALSE;
        jmp$notify_job_scheduler_of_job (job_class, jmc$kjl_undefined_index);
      IFEND;
    FOREND;
    osp$clear_mainframe_sig_lock (qfv$kjl_lock);
  PROCEND qfp$clear_server_job_classes;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] qfp$determine_needed_priorities', EJECT ??
*copy qfh$determine_needed_priorities

  PROCEDURE [XDCL, #GATE] qfp$determine_needed_priorities
    (    leveler_job_class_data: jmt$jl_job_class_data;
     VAR job_class_priorities: jmt$jl_job_class_priorities);

    VAR
      current_clock_time: jmt$clock_time,
      eligible_job_categories: boolean,
      job_class: jmt$job_class,
      kjl_index: jmt$kjl_index,
      number_of_jobs_needed: ost$non_negative_integers,
      profile_job_class: jmt$job_class;

    current_clock_time := #FREE_RUNNING_CLOCK (0);
    osp$set_mainframe_sig_lock (qfv$kjl_lock);
    FOR profile_job_class := 1 TO jmv$maximum_profile_index DO
      job_class := jmv$profile_index_to_job_class [profile_job_class];
      number_of_jobs_needed := leveler_job_class_data [profile_job_class].termination_count +
            leveler_job_class_data [profile_job_class].room_in_class;
      kjl_index := jmv$known_job_list.queued_class_entries [job_class].first_queued_class_entry;
      WHILE (kjl_index <> jmc$kjl_undefined_index) AND (number_of_jobs_needed > 0) DO
        eligible_job_categories := ((jmv$job_scheduler_table.initiation_required_categories *
              jmv$kjl_p^ [kjl_index].job_category_set) = jmv$job_scheduler_table.
              initiation_required_categories) AND ((jmv$job_scheduler_table.initiation_excluded_categories *
              jmv$kjl_p^ [kjl_index].job_category_set) = $jmt$job_category_set []);
        IF eligible_job_categories THEN
          number_of_jobs_needed := number_of_jobs_needed - 1;
          IF number_of_jobs_needed > 0 THEN
            kjl_index := jmv$kjl_p^ [kjl_index].class_forward_link;
          IFEND;
        ELSE
          kjl_index := jmv$kjl_p^ [kjl_index].class_forward_link;
        IFEND;
      WHILEND;
      IF kjl_index = jmc$kjl_undefined_index THEN
        job_class_priorities [profile_job_class].job_priority :=
              jmv$job_class_table_p^ [job_class].selection_priority.initial;
        job_class_priorities [profile_job_class].based_on_selection_priority := TRUE;
      ELSE
        job_class_priorities [profile_job_class].job_priority :=
              qfp$job_selection_priority (current_clock_time, kjl_index);
        job_class_priorities [profile_job_class].based_on_selection_priority := FALSE;
      IFEND;
      IF job_class_priorities [profile_job_class].job_priority <
            jmv$job_class_table_p^ [job_class].selection_priority.threshold THEN
        job_class_priorities [profile_job_class].job_priority :=
              jmv$job_class_table_p^ [job_class].selection_priority.threshold;
      IFEND;
    FOREND;
    osp$clear_mainframe_sig_lock (qfv$kjl_lock);
  PROCEND qfp$determine_needed_priorities;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] qfp$determine_need_for_jobs', EJECT ??
*copy qfh$determine_need_for_jobs

{ NOTE:
{   The KJL does not need to be locked during this request since no linkages
{ are changed and only one copy of the job leveler can be active at a time.

  PROCEDURE [XDCL, #GATE] qfp$determine_need_for_jobs
    (VAR leveler_job_class_data: jmt$jl_job_class_data);

    VAR
      job_class: jmt$job_class,
      number_of_jobs_needed: jmt$job_count_range,
      profile_job_class: jmt$job_class;

    FOR profile_job_class := 1 TO jmv$maximum_profile_index DO
      job_class := jmv$profile_index_to_job_class [profile_job_class];
      IF NOT jmv$job_class_table_p^ [job_class].enable_class_initiation THEN
        leveler_job_class_data [profile_job_class].room_in_class := 0;
        leveler_job_class_data [profile_job_class].class_maximum := 0;
        leveler_job_class_data [profile_job_class].termination_count := 0;
        number_of_jobs_needed := 0;
      ELSE
        leveler_job_class_data [profile_job_class].termination_count :=
              jmv$known_job_list.queued_class_entries [job_class].termination_count;
        leveler_job_class_data [profile_job_class].class_maximum :=
              jmv$job_class_table_p^ [job_class].initiation_level.preferred;
        IF (leveler_job_class_data [profile_job_class].class_maximum - jmv$job_counts.
              job_class_counts [job_class].initiated_jobs) < 0 THEN
          leveler_job_class_data [profile_job_class].room_in_class := 0;
        ELSE
          leveler_job_class_data [profile_job_class].room_in_class :=
                leveler_job_class_data [profile_job_class].class_maximum - jmv$job_counts.
                job_class_counts [job_class].initiated_jobs;
        IFEND;
        IF (leveler_job_class_data [profile_job_class].termination_count +
              leveler_job_class_data [profile_job_class].room_in_class) >
              UPPERVALUE (jmt$job_count_range) THEN
          number_of_jobs_needed := UPPERVALUE (jmt$job_count_range);
        ELSE
          number_of_jobs_needed := leveler_job_class_data [profile_job_class].termination_count +
                leveler_job_class_data [profile_job_class].room_in_class;
        IFEND;
      IFEND;
      jmv$known_job_list.queued_class_entries [job_class].number_of_jobs_needed := number_of_jobs_needed;
      jmv$known_job_list.queued_class_entries [job_class].termination_count := 0;
    FOREND;
  PROCEND qfp$determine_need_for_jobs;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] qfp$discard_client_jobs', EJECT ??
*copy qfh$discard_client_jobs

  PROCEDURE [XDCL, #GATE] qfp$discard_client_jobs
    (    client_mainframe_id: pmt$binary_mainframe_id);

    VAR
      client_in_kjl: boolean,
      kjl_index: jmt$kjl_index,
      kjl_client_index: jmt$kjl_client_index,
      next_kjl_index: jmt$kjl_index;

    osp$set_mainframe_sig_lock (qfv$kjl_lock);

    find_client_mainframe_id (client_mainframe_id, { add_if_not_found } FALSE, client_in_kjl,
          kjl_client_index);
    IF client_in_kjl THEN
      kjl_index := jmv$known_job_list.client_data.state_data [kjl_client_index].first_entry;
      WHILE (kjl_index <> jmc$kjl_undefined_index) DO
        next_kjl_index := jmv$kjl_p^ [kjl_index].client_forward_link;
        IF (jmv$kjl_p^ [kjl_index].entry_kind = jmc$kjl_assigned_entry) THEN
          qfp$relink_kjl_client (kjl_index, jmc$kjl_client_undefined);
          qfp$relink_kjl_application (kjl_index, jmc$ve_input_application_index, jmc$kjl_application_new);
          qfp$relink_kjl_entry (kjl_index, jmv$kjl_p^ [kjl_index].job_class, jmc$kjl_queued_entry);
        IFEND;
        kjl_index := next_kjl_index;
      WHILEND
    IFEND;
    osp$clear_mainframe_sig_lock (qfv$kjl_lock);
  PROCEND qfp$discard_client_jobs;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] qfp$discard_server_jobs', EJECT ??
*copy qfh$discard_server_jobs

  PROCEDURE [XDCL, #GATE] qfp$discard_server_jobs
    (    server_mainframe_id: pmt$binary_mainframe_id);

    VAR
      job_class: jmt$job_class,
      kjl_index: jmt$kjl_index,
      kjl_server_index: jmt$kjl_server_index,
      next_kjl_index: jmt$kjl_index,
      scheduler_has_jobs: boolean,
      server_in_kjl: boolean;

    osp$set_mainframe_sig_lock (qfv$kjl_lock);

    find_server_mainframe_id (server_mainframe_id, { add_if_not_found } FALSE, server_in_kjl,
          kjl_server_index);
    IF server_in_kjl THEN
      scheduler_has_jobs := FALSE;

{ Check to see if the job scheduler has any jobs for this server in the job
{ candidate queue.  If it doesn't don't bother the scheduler.  If the system
{ is in an idled state (an idle jobs request would do it) the scheduler may not
{ be willing to clean out the candidate queue.  The scheduler should never go
{ idle with jobs in the candidate queue.

    /search_candidate_queue_for_jobs/
      FOR job_class := jmc$system_job_class TO jmv$maximum_job_class_in_use DO
        IF jmv$candidate_queued_jobs [job_class].candidate_available THEN
          IF (jmv$kjl_p^ [jmv$candidate_queued_jobs [job_class].kjl_index].server_index =
                kjl_server_index) THEN
            scheduler_has_jobs := TRUE;
            EXIT /search_candidate_queue_for_jobs/;
          IFEND;
        IFEND;
      FOREND /search_candidate_queue_for_jobs/;

      IF scheduler_has_jobs THEN
        jmp$force_candidate_refresh ({ flush_candidate_queue } TRUE);
      IFEND;

      kjl_index := jmv$known_job_list.server_data.state_data [kjl_server_index].first_entry;
      WHILE (kjl_index <> jmc$kjl_undefined_index) DO
        next_kjl_index := jmv$kjl_p^ [kjl_index].server_forward_link;
        IF (jmv$kjl_p^ [kjl_index].entry_kind = jmc$kjl_queued_entry) THEN
          qfp$relink_kjl_server (kjl_index, jmc$kjl_server_undefined);
          qfp$relink_kjl_application (kjl_index, jmc$ve_input_application_index, jmc$kjl_application_unused);
          qfp$relink_kjl_entry (kjl_index, jmv$kjl_p^ [kjl_index].job_class, jmc$kjl_unused_entry);
        IFEND;
        kjl_index := next_kjl_index;
      WHILEND
    IFEND;
    osp$clear_mainframe_sig_lock (qfv$kjl_lock);
  PROCEND qfp$discard_server_jobs;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] qfp$get_server_jobs', EJECT ??
*copy qfh$get_server_jobs

  PROCEDURE [XDCL, #GATE] qfp$get_server_jobs
    (    server_mainframe_id: pmt$binary_mainframe_id;
         server_job_list_p: { output } ^jmt$jl_server_job_list;
     VAR server_job_count: jmt$job_count_range);

    VAR
      kjl_index: jmt$kjl_index,
      kjl_server_index: jmt$kjl_server_index,
      server_in_kjl: boolean;

    server_job_count := 0;
    osp$set_mainframe_sig_lock (qfv$kjl_lock);

    find_server_mainframe_id (server_mainframe_id, { add_if_not_found } FALSE, server_in_kjl,
          kjl_server_index);
    IF server_in_kjl THEN
      kjl_index := jmv$known_job_list.server_data.state_data [kjl_server_index].first_entry;
      WHILE (kjl_index <> jmc$kjl_undefined_index) DO
        server_job_count := server_job_count + 1;
        server_job_list_p^ [server_job_count].system_job_name := jmv$kjl_p^ [kjl_index].system_job_name;
        server_job_list_p^ [server_job_count].kjl_entry_kind := jmv$kjl_p^ [kjl_index].entry_kind;
        server_job_list_p^ [server_job_count].server_kjl_index := jmv$kjl_p^ [kjl_index].server_kjl_index;
        kjl_index := jmv$kjl_p^ [kjl_index].server_forward_link;
      WHILEND
    IFEND;
    osp$clear_mainframe_sig_lock (qfv$kjl_lock);
  PROCEND qfp$get_server_jobs;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] qfp$register_job_leveler', EJECT ??
*copy qfh$register_job_leveler

  PROCEDURE [XDCL, #GATE] qfp$register_job_leveler;

    VAR
      job_class: jmt$job_class;

    pmp$get_executing_task_gtid (jmv$known_job_list.application_table [jmc$ve_input_application_index].
          global_task_id);
    FOR job_class := jmc$system_job_class TO jmv$maximum_job_class_in_use DO
      jmv$known_job_list.queued_class_entries [job_class].termination_count := 0;
    FOREND;
  PROCEND qfp$register_job_leveler;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] qfp$server_job_begin', EJECT ??
*copy qfh$server_job_begin

  PROCEDURE [XDCL, #GATE] qfp$server_job_begin
    (    job_begin_information: jmt$jl_server_job_end_info;
     VAR job_terminated: boolean;
     VAR login_family: ost$name);

    VAR
      client_in_kjl: boolean,
      kjl_client_index: jmt$kjl_client_index,
      server_kjl_index: jmt$kjl_index,
      unassigned_job_index: ost$non_negative_integers;

    osp$set_mainframe_sig_lock (qfv$kjl_lock);
    find_client_mainframe_id (job_begin_information.client_mainframe_id, { add_if_not_found } TRUE,
          client_in_kjl, kjl_client_index);
    IF client_in_kjl THEN
      determine_server_kjl_index (kjl_client_index, job_begin_information.system_job_name,
            job_begin_information.server_kjl_index, server_kjl_index);
      IF server_kjl_index <> jmc$kjl_undefined_index THEN
        job_terminated := jmv$kjl_p^ [server_kjl_index].entry_kind = jmc$kjl_terminated_entry;
        qfp$relink_kjl_entry (server_kjl_index, jmv$kjl_p^ [server_kjl_index].job_class,
              jmc$kjl_initiated_entry);
        login_family := jmv$kjlx_p^ [server_kjl_index].login_user_identification.family;
      ELSE

{ Trap code...
{       osp$system_error ('The server KJL lost a client job.', NIL);

        login_family := '';
      IFEND;
    ELSE

{ Trap code...
{     osp$system_error ('The server KJL lost a client mainframe.', NIL);

      login_family := '';
    IFEND;
    osp$clear_mainframe_sig_lock (qfv$kjl_lock);
  PROCEND qfp$server_job_begin;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] qfp$server_job_end', EJECT ??
*copy qfh$server_job_end

  PROCEDURE [XDCL, #GATE] qfp$server_job_end
    (    job_end_information: jmt$jl_server_job_end_info);

    VAR
      client_in_kjl: boolean,
      kjl_client_index: jmt$kjl_client_index,
      server_kjl_index: jmt$kjl_index,
      unassigned_job_index: ost$non_negative_integers;

    osp$set_mainframe_sig_lock (qfv$kjl_lock);
    find_client_mainframe_id (job_end_information.client_mainframe_id, { add_if_not_found } TRUE,
          client_in_kjl, kjl_client_index);
    IF client_in_kjl THEN
      determine_server_kjl_index (kjl_client_index, job_end_information.system_job_name,
            job_end_information.server_kjl_index, server_kjl_index);
      IF server_kjl_index <> jmc$kjl_undefined_index THEN
        IF job_end_information.job_requests_restart THEN

{ The job's KJL entry is already in the correct server and client thread.

          qfp$relink_kjl_application (server_kjl_index, jmc$ve_input_application_index,
                jmc$kjl_application_acquired);
          qfp$relink_kjl_entry (server_kjl_index, jmv$kjl_p^ [server_kjl_index].job_class,
                jmc$kjl_assigned_entry);
        ELSE
          qfp$relink_kjl_application (server_kjl_index, jmc$ve_input_application_index,
                jmc$kjl_application_unused);
          qfp$relink_kjl_client (server_kjl_index, jmc$kjl_client_undefined);
          qfp$relink_kjl_server (server_kjl_index, jmc$kjl_server_undefined);
          qfp$relink_kjl_entry (server_kjl_index, jmv$kjl_p^ [server_kjl_index].job_class,
                jmc$kjl_unused_entry);
        IFEND;
      ELSE

{ Trap code...
{       osp$system_error ('The server KJL lost a client job.', NIL);

      IFEND;
    ELSE

{ Trap code...
{     osp$system_error ('The server KJL lost a client mainframe.', NIL);

    IFEND;
    osp$clear_mainframe_sig_lock (qfv$kjl_lock);
  PROCEND qfp$server_job_end;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] qfp$set_leveler_ready', EJECT ??
*copy qfh$set_leveler_ready

  PROCEDURE [XDCL, #GATE] qfp$set_leveler_ready
    (    ready_leveler: boolean);

    qfv$leveler_readied := ready_leveler;
  PROCEND qfp$set_leveler_ready;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] qfp$unassign_client_jobs', EJECT ??
*copy qfh$unassign_client_jobs

  PROCEDURE [XDCL, #GATE] qfp$unassign_client_jobs
    (    client_mainframe_id: pmt$binary_mainframe_id;
         unassigned_job_list_p: ^jmt$jl_unassigned_job_list);

    VAR
      client_in_kjl: boolean,
      kjl_client_index: jmt$kjl_client_index,
      server_kjl_index: jmt$kjl_index,
      unassigned_job_index: ost$non_negative_integers;

    osp$set_mainframe_sig_lock (qfv$kjl_lock);
    find_client_mainframe_id (client_mainframe_id, { add_if_not_found } TRUE, client_in_kjl,
          kjl_client_index);
    IF client_in_kjl AND (unassigned_job_list_p <> NIL) THEN
      FOR unassigned_job_index := 1 TO UPPERBOUND (unassigned_job_list_p^) DO
        determine_server_kjl_index (kjl_client_index, unassigned_job_list_p^ [unassigned_job_index].
              system_job_name, unassigned_job_list_p^ [unassigned_job_index].server_kjl_index,
              server_kjl_index);
        IF server_kjl_index <> jmc$kjl_undefined_index THEN
          qfp$relink_kjl_application (server_kjl_index, jmc$ve_input_application_index,
                jmc$kjl_application_new);
          qfp$relink_kjl_client (server_kjl_index, jmc$kjl_client_undefined);
          qfp$relink_kjl_entry (server_kjl_index, jmv$kjl_p^ [server_kjl_index].job_class,
                jmc$kjl_queued_entry);

        ELSE
          osp$system_error ('The server KJL lost a client job.', NIL);
        IFEND;
      FOREND;
    ELSE
      IF NOT client_in_kjl THEN
        osp$system_error ('The server KJL lost a client mainframe.', NIL);
      IFEND;
    IFEND;
    osp$clear_mainframe_sig_lock (qfv$kjl_lock);
  PROCEND qfp$unassign_client_jobs;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] qfp$unassign_server_jobs', EJECT ??
*copy qfh$unassign_server_jobs

  PROCEDURE [XDCL, #GATE] qfp$unassign_server_jobs
    (    server_mainframe_id: pmt$binary_mainframe_id;
         unassign_all_jobs: boolean;
         job_class_priorities: jmt$jl_job_class_priorities;
         unassigned_job_list_p { output } : ^jmt$jl_unassigned_job_list;
     VAR number_of_unassigned_jobs: jmt$job_count_range);

    VAR
      current_clock_time: jmt$clock_time,
      job_class: jmt$job_class,
      kjl_index: jmt$kjl_index,
      kjl_server_index: jmt$kjl_server_index,
      next_kjl_index: jmt$kjl_index,
      server_in_kjl: boolean;

    number_of_unassigned_jobs := 0;
    current_clock_time := #FREE_RUNNING_CLOCK (0);
    osp$set_mainframe_sig_lock (qfv$kjl_lock);

    find_server_mainframe_id (server_mainframe_id, { add_if_not_found } FALSE, server_in_kjl,
          kjl_server_index);
    IF server_in_kjl THEN
      IF unassign_all_jobs THEN
        jmp$force_candidate_refresh ({ flush_candidate_queue } TRUE);
      IFEND;
      kjl_index := jmv$known_job_list.server_data.state_data [kjl_server_index].last_entry;
      WHILE (kjl_index <> jmc$kjl_undefined_index) AND (number_of_unassigned_jobs <
            UPPERBOUND (unassigned_job_list_p^)) DO
        next_kjl_index := jmv$kjl_p^ [kjl_index].server_reverse_link;
        IF (jmv$kjl_p^ [kjl_index].entry_kind = jmc$kjl_queued_entry) AND
              (jmv$kjl_p^ [kjl_index].application_state <= jmc$kjl_application_new) THEN
          job_class := jmv$kjl_p^ [kjl_index].job_class;
          jmv$kjl_p^ [kjl_index].job_priority := qfp$job_selection_priority (current_clock_time, kjl_index);
          IF unassign_all_jobs OR (jmv$known_job_list.queued_class_entries [job_class].number_of_jobs_needed =
                0) OR (jmv$kjl_p^ [kjl_index].job_priority < job_class_priorities
                [jmv$job_class_table_p^ [job_class].profile_index].job_priority) THEN
            number_of_unassigned_jobs := number_of_unassigned_jobs + 1;
            unassigned_job_list_p^ [number_of_unassigned_jobs].system_job_name :=
                  jmv$kjl_p^ [kjl_index].system_job_name;
            unassigned_job_list_p^ [number_of_unassigned_jobs].server_kjl_index :=
                  jmv$kjl_p^ [kjl_index].server_kjl_index;
            qfp$relink_kjl_server (kjl_index, jmc$kjl_server_undefined);
            qfp$relink_kjl_application (kjl_index, jmc$ve_input_application_index,
                  jmc$kjl_application_unused);
            qfp$relink_kjl_entry (kjl_index, jmv$kjl_p^ [kjl_index].job_class, jmc$kjl_unused_entry);
          IFEND;
        IFEND;
        kjl_index := next_kjl_index;
      WHILEND
    IFEND;
    osp$clear_mainframe_sig_lock (qfv$kjl_lock);
  PROCEND qfp$unassign_server_jobs;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] qfp$update_server_priorities', EJECT ??
*copy qfh$update_server_priorities

  PROCEDURE [XDCL, #GATE] qfp$update_server_priorities
    (    highest_server_priorities: jmt$jl_server_job_priorities);

    VAR
      job_class: jmt$job_class,
      profile_job_class: jmt$job_class;

    osp$set_mainframe_sig_lock (qfv$kjl_lock);
    FOR profile_job_class := 1 TO jmv$maximum_profile_index DO
      job_class := jmv$profile_index_to_job_class [profile_job_class];
      jmv$known_job_list.queued_class_entries [job_class].server_mainframe_priority :=
            highest_server_priorities [profile_job_class];
      IF jmv$known_job_list.queued_class_entries [job_class].class_blocked_for_initiation THEN
        jmp$notify_job_scheduler_of_job (job_class, jmc$kjl_undefined_index);
        jmv$known_job_list.queued_class_entries [job_class].class_blocked_for_initiation := FALSE;
      IFEND;
    FOREND;
    osp$clear_mainframe_sig_lock (qfv$kjl_lock);
  PROCEND qfp$update_server_priorities;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] qfp$verify_client_assigned_jobs', EJECT ??
*copy qfh$verify_client_assigned_jobs

  PROCEDURE [XDCL, #GATE] qfp$verify_client_assigned_jobs
    (    client_mainframe_id: pmt$binary_mainframe_id;
         server_job_list_p: ^jmt$jl_server_job_list;
         missing_job_list_p: { output } ^jmt$jl_missing_job_list;
     VAR missing_job_count: jmt$job_count_range);

    VAR
      client_in_kjl: boolean,
      job_in_server_list: boolean,
      kjl_index: jmt$kjl_index,
      kjl_client_index: jmt$kjl_client_index,
      maximum_server_job_index: jmt$job_count_range,
      next_kjl_index: jmt$kjl_index,
      server_job_list_index: jmt$job_count_range;

    missing_job_count := 0;
    osp$set_mainframe_sig_lock (qfv$kjl_lock);

    find_client_mainframe_id (client_mainframe_id, { add_if_not_found } FALSE, client_in_kjl,
          kjl_client_index);
    IF client_in_kjl THEN
      IF server_job_list_p = NIL THEN
        maximum_server_job_index := 0;
      ELSE
        maximum_server_job_index := UPPERBOUND (server_job_list_p^);
      IFEND;

      kjl_index := jmv$known_job_list.client_data.state_data [kjl_client_index].first_entry;
      WHILE (kjl_index <> jmc$kjl_undefined_index) DO
        next_kjl_index := jmv$kjl_p^ [kjl_index].client_forward_link;

{ Find the job in the server job list.  If it is there, verify the job state.  If it is not
{ there, the job was lost and should be made available for initiation again if it was still
{ in the queued state.

        job_in_server_list := FALSE;

      /search_for_job_in_server_list/
        FOR server_job_list_index := 1 TO maximum_server_job_index DO
          IF jmv$kjl_p^ [kjl_index].system_job_name = server_job_list_p^ [server_job_list_index].
                system_job_name THEN
            job_in_server_list := TRUE;
            IF jmv$kjl_p^ [kjl_index].entry_kind <> server_job_list_p^ [server_job_list_index].
                  kjl_entry_kind THEN

{ This can happen if job begin hasn't updated the server yet.  This can also happen if
{ a job has been queued for restart due to job recovery on the client.
{ The state of the job on the client is the correct state so change the state of
{ the job on the server.

{ If the entry is queued, the job is "assigned" to the client.  If the entry is
{ initiated, don't change anything since the client will be updating the server
{ shortly to say that the job is initiated.

              IF server_job_list_p^ [server_job_list_index].kjl_entry_kind = jmc$kjl_queued_entry THEN
                qfp$relink_kjl_client (kjl_index, kjl_client_index);
                qfp$relink_kjl_application (kjl_index, jmc$ve_input_application_index,
                      jmc$kjl_application_acquired);
                qfp$relink_kjl_entry (kjl_index, jmv$kjl_p^ [kjl_index].job_class, jmc$kjl_assigned_entry);
              IFEND;
            IFEND;
            EXIT /search_for_job_in_server_list/;
          IFEND;
        FOREND /search_for_job_in_server_list/;

        IF NOT job_in_server_list THEN

{ If the job was queued, make it available for initiation.  If the job initiated
{ then the job must be removed from the KJL.

          IF (jmv$kjl_p^ [kjl_index].entry_kind = jmc$kjl_queued_entry) THEN
            qfp$relink_kjl_client (kjl_index, jmc$kjl_client_undefined);
            qfp$relink_kjl_application (kjl_index, jmc$ve_input_application_index, jmc$kjl_application_new);
          ELSE
            IF missing_job_list_p <> NIL THEN
              IF missing_job_count < UPPERBOUND (missing_job_list_p^) THEN
                missing_job_count := missing_job_count + 1;
                missing_job_list_p^ [missing_job_count].system_job_name :=
                      jmv$kjl_p^ [kjl_index].system_job_name;
                missing_job_list_p^ [missing_job_count].login_family :=
                      jmv$kjlx_p^ [kjl_index].login_user_identification.family;
              IFEND;
            IFEND;
            qfp$relink_kjl_application (kjl_index, jmc$ve_input_application_index,
                  jmc$kjl_application_unused);
            qfp$relink_kjl_client (kjl_index, jmc$kjl_client_undefined);
            qfp$relink_kjl_server (kjl_index, jmc$kjl_server_undefined);
            qfp$relink_kjl_entry (kjl_index, jmv$kjl_p^ [kjl_index].job_class, jmc$kjl_unused_entry);
          IFEND;
        IFEND;
        kjl_index := next_kjl_index;
      WHILEND
    IFEND;
    osp$clear_mainframe_sig_lock (qfv$kjl_lock);
  PROCEND qfp$verify_client_assigned_jobs;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] qfp$verify_inactive_server', EJECT ??
*copyc qfh$verify_inactive_server

  PROCEDURE [XDCL, #GATE] qfp$verify_inactive_server
    (    server_mainframe_id: pmt$binary_mainframe_id;
     VAR server_inactive: boolean);

    VAR
      kjl_index: jmt$kjl_index,
      kjl_server_index: jmt$kjl_server_index,
      next_kjl_index: jmt$kjl_index,
      server_in_kjl: boolean;

    server_inactive := TRUE;
    osp$set_mainframe_sig_lock (qfv$kjl_lock);

    find_server_mainframe_id (server_mainframe_id, { add_if_not_found } FALSE, server_in_kjl,
          kjl_server_index);
    IF server_in_kjl THEN
      kjl_index := jmv$known_job_list.server_data.state_data [kjl_server_index].first_entry;
      WHILE (kjl_index <> jmc$kjl_undefined_index) DO
        next_kjl_index := jmv$kjl_p^ [kjl_index].server_forward_link;
        IF (jmv$kjl_p^ [kjl_index].entry_kind = jmc$kjl_queued_entry) AND
              (jmv$kjl_p^ [kjl_index].application_state <= jmc$kjl_application_new) THEN
          server_inactive := FALSE;

          osp$system_error ('Inactive Server has uninitiated jobs on the Client.', NIL);

          qfp$relink_kjl_server (kjl_index, jmc$kjl_server_undefined);
          qfp$relink_kjl_application (kjl_index, jmc$ve_input_application_index, jmc$kjl_application_unused);
          qfp$relink_kjl_entry (kjl_index, jmv$kjl_p^ [kjl_index].job_class, jmc$kjl_unused_entry);
        IFEND;
        kjl_index := next_kjl_index;
      WHILEND
    IFEND;
    osp$clear_mainframe_sig_lock (qfv$kjl_lock);
  PROCEND qfp$verify_inactive_server;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] qfp$wait_for_leveler_deactivate', EJECT ??
*copy qfh$wait_for_leveler_deactivate

  PROCEDURE [XDCL, #GATE] qfp$wait_for_leveler_deactivate
    (    wait_time_sec: ost$non_negative_integers;
     VAR leveler_deactivated: boolean);

    CONST
      number_of_us_in_a_second = 1000000;

    VAR
      current_time: jmt$clock_time,
      end_time: jmt$clock_time,
      ignore_status: ost$status,
      kjl_server_index: jmt$kjl_server_index,
      kjl_index: jmt$kjl_index,
      queued_job_found: boolean,
      start_time: jmt$clock_time;

    start_time := #FREE_RUNNING_CLOCK (0);
    end_time := start_time + wait_time_sec * number_of_us_in_a_second;
    current_time := start_time;
    leveler_deactivated := FALSE;

{ Lock and unlock the KJL to ensure synchronization.  This ensures that no job levelers
{ are in the process of modifying the KJL.  Any additional requests for levelers to
{ modify the KJL are controlled by the variable jmv$leveler_profile_loading.

    osp$set_mainframe_sig_lock (qfv$kjl_lock);
    osp$clear_mainframe_sig_lock (qfv$kjl_lock);

{ Wait for other job levelers to return jobs to this mainframe.  Once no jobs are
{ assigned the request can continue.

    WHILE (current_time <= end_time) AND (jmv$known_job_list.state_data [jmc$kjl_assigned_entry].
          number_of_entries > 0) DO
      pmp$delay (1000, ignore_status);
      current_time := #FREE_RUNNING_CLOCK (0);
      #SPOIL (jmv$known_job_list.state_data);
    WHILEND;

{ Wait for the job leveler on this mainframe to return all jobs.  Go through each
{ server thread and verify that there are no longer any jobs assigned by that server.

    IF current_time <= end_time THEN

    /wait_for_client_levelers/
      REPEAT
        queued_job_found := FALSE;
        osp$set_mainframe_sig_lock (qfv$kjl_lock);

      /check_each_client_leveler/
        FOR kjl_server_index := jmc$kjl_server_this_mainframe + 1 TO UPPERVALUE (jmt$kjl_server_index) DO
          IF jmv$known_job_list.server_data.state_data [kjl_server_index].mainframe_id <>
                null_binary_mainframe_id THEN
            kjl_index := jmv$known_job_list.server_data.state_data [kjl_server_index].first_entry;

            WHILE kjl_index <> jmc$kjl_undefined_index DO
              IF jmv$kjl_p^ [kjl_index].entry_kind = jmc$kjl_queued_entry THEN
                queued_job_found := TRUE;
                EXIT /check_each_client_leveler/;
              ELSE
                kjl_index := jmv$kjl_p^ [kjl_index].server_forward_link;
              IFEND;
            WHILEND;
          IFEND;
        FOREND /check_each_client_leveler/;
        osp$clear_mainframe_sig_lock (qfv$kjl_lock);
        IF queued_job_found THEN
          pmp$delay (1000, ignore_status);
          current_time := #FREE_RUNNING_CLOCK (0);
        IFEND;
      UNTIL (current_time > end_time) OR (NOT queued_job_found);
      leveler_deactivated := NOT queued_job_found;
    IFEND;

  PROCEND qfp$wait_for_leveler_deactivate;
?? OLDTITLE ??
MODEND qfm$queue_file_leveler_manager;
