?? RIGHT := 110 ??
?? TITLE := 'NOS/VE File Server : Client : Remote Procedure Call' ??
MODULE dfm$client_remote_procedur_call;
{
{   This module contains the client side of the remote procedure call
{   processing.  The client side drives the remote procedure call mechanism,
{   looping on sending / receiving data.  The remote procedure call is
{   broken into multiple transactions if there is too much data to be sent.
{   Data is never sent both directions on one transaction. If the server
{   detects that the request needs to be restarted and abnormal status of
{   of dfe$restart_server_request is returned to the client and the
{   complete request is set over again.  Changes in this module may need
{   to be reflected in module DFM$CLIENT_REMOTE_CORE_CALL.
?? NEWTITLE := '  Global Declarations Referenced by this module' ??
?? PUSH (LISTEXT := ON) ??
*copyc dfd$driver_queue_types
*copyc dfd$request_package
*copyc dfe$error_condition_codes
*copyc dfk$keypoints
*copyc dft$cpu_queue
*copyc dft$job_recovery_location
*copyc dft$procedure_version
*copyc dft$rpc_parameters
*copyc dft$rpc_queue_entry_location
*copyc dft$rpc_queue_entry_loc_int
*copyc dft$rpc_buffer_header
*copyc dft$rpc_procedure_address_list
*copyc dft$server_location
*copyc osd$virtual_address
*copyc oss$job_paged_literal
*copyc oss$task_private
*copyc ost$caller_identifier
*copyc ost$status
*copyc pme$insufficient_privilege
?? POP ??
?? EJECT ??
*copyc avp$family_administrator
*copyc avp$system_administrator
*copyc clp$validate_name
*copyc dfc$test_jr_constants
*copyc dfi$display
*copyc dfi$log_display
*copyc dfp$await_subsystem_action
*copyc dfp$check_job_server
*copyc dfp$check_queue_entry_assigned
*copyc dfp$clear_driver_flags
*copyc dfp$convert_queue_entry_loc
*copyc dfp$fetch_queue_entry
*copyc dfp$fetch_served_family_info
*copyc dfp$fetch_served_family_state
*copyc dfp$find_mainframe_id
*copyc dfp$form_inquiry_tracer
*copyc dfp$get_qit_p_from_direct_index
*copyc dfp$get_queue_directory_index
*copyc dfp$get_task_queue_entry
*copyc dfp$initialize_rma_list
*copyc dfp$locate_served_family
*copyc dfp$page_count
*copyc dfp$queue_client_task_request
*copyc dfp$queue_inquiry_request
*copyc dfp$recover_job
*copyc dfp$release_task_queue_entry
*copyc dfp$set_invalid_family_index
*copyc dfp$set_job_validation_change
*copyc dfp$touch_pages
*copyc dfp$validate_rpc_status
*copyc dfp$word_boundary
*copyc dfv$file_server_debug_enabled
*copyc dfv$job_recovery_rpc_requests
*copyc dfv$p_queue_interface_directory
*copyc dfv$procedure_address_list
*copyc dfv$send_command_and_data_flags
*copyc dfv$send_command_flags
*copyc dfv$send_ready_for_data_flags
*copyc i#current_sequence_position
*copyc mmp$free_pages
*copyc ofp$display_status_message
*copyc osp$append_status_integer
*copyc osp$append_status_parameter
*copyc osp$begin_subsystem_activity
*copyc osp$disestablish_cond_handler
*copyc osp$end_subsystem_activity
*copyc osp$establish_condition_handler
*copyc osp$log_job_recovery_message
*copyc osp$recoverable_system_error
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc osp$verify_system_privilege
*copyc pmh$continue_to_cause
*copyc pmh$establish_condition_handler
*copyc pmp$continue_to_cause
*copyc pmp$delay
*copyc pmp$disestablish_cond_handler
*copyc pmp$establish_condition_handler
*copyc pmp$continue_to_cause
*copyc pmp$get_executing_task_gtid
*copyc pmp$get_job_names
*copyc pmp$long_term_wait
*copyc syp$hang_if_job_jrt_set
*copyc syp$pop_inhibit_job_recovery
*copyc syp$push_inhibit_job_recovery
?? TITLE := '  Global Declarations Declared by this module', EJECT ??
 VAR
   dfv$recovery_task: [XDCL, oss$task_private] boolean := FALSE;
?? TITLE := ' [XDCL, #GATE] dfp$begin_remote_procedure_call', EJECT ??
*copyc dfh$begin_remote_procedure_call
?? EJECT ??
  PROCEDURE [XDCL, #GATE] dfp$begin_remote_procedure_call
    (    server_location: dft$server_location;
         allowed_when_server_deactivated: boolean;
     VAR queue_entry_location: dft$rpc_queue_entry_location;
     VAR p_send_to_server_params: dft$p_send_parameters;
     VAR p_send_data: dft$p_send_data;
     VAR status: ost$status);


{ PURPOSE:
{   This condition handler is used around the code that is reserving queue entries to the server in
{   the case of job recovery.  The file server queues are kept in server wired and the queue definition
{   is not recovered.  If the job is recovered while it is doing dfp$begin_remote_procedure_call
{   the condition handler will perform a non-local exit with an abnormal status of
{   DFE$SERVER_NOT_ACTIVE - almost all callers are prepared for this.
{
    PROCEDURE begin_rpc_job_rec_cond_handler
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        display_status: ost$status;

      IF (condition.selector = pmc$user_defined_condition) AND
            (condition.user_condition_name = 'OSC$JOB_RECOVERY') THEN
        IF subsystem_activity_began THEN
          osp$end_subsystem_activity;
        IFEND;
        IF dfv$file_server_debug_enabled THEN
          display_trace_back;
        IFEND;
        osp$log_job_recovery_message (
              ' Job recovery rollback dfp$begin_remote_procedure_call',
              display_status);
        osp$set_status_abnormal (dfc$file_server_id, dfe$server_not_active,
              ' job recovery rollback - begin_rpc  ', status);
        IF dfv$file_server_debug_enabled THEN
          display_trace_back;
        IFEND;
        EXIT dfp$begin_remote_procedure_call;
      IFEND;

      pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);

    PROCEND begin_rpc_job_rec_cond_handler;


    VAR
      caller_id: ost$caller_identifier,
      p_cpu_queue_entry: ^dft$cpu_queue_entry,
      p_cpu_queue_header: ^dft$cpu_queue_header,
      p_driver_queue_entry: ^dft$driver_queue_entry,
      p_queue_interface_table: dft$p_queue_interface_table,
      p_send_buffer_header: ^dft$buffer_header,
      p_send_rpc_buffer_header: ^dft$rpc_buffer_header,
      queue_entry_loc_int: dft$rpc_queue_entry_loc_int,
      subsystem_activity_began: boolean;

    status.normal := TRUE;
    #KEYPOINT (osk$entry, osk$m * $INTEGER (allowed_when_server_deactivated),
          dfk$begin_remote_procedure_call);
    #CALLER_ID (caller_id);
    IF caller_id.ring > osc$tsrv_ring THEN
      osp$set_status_abnormal ('PM', pme$insufficient_privilege, '', status);
      RETURN;
    IFEND;
    subsystem_activity_began := FALSE;
    #SPOIL (subsystem_activity_began);

    osp$establish_condition_handler (^begin_rpc_job_rec_cond_handler, FALSE);
    locate_server (server_location, p_queue_interface_table, queue_entry_loc_int, status);
    IF status.normal THEN
      p_cpu_queue_header := ^p_queue_interface_table^.queue_directory.cpu_queue_pva_directory
           [queue_entry_loc_int.queue_index].p_cpu_queue^.queue_header;
     IF (p_cpu_queue_header^.partner_status.server_state = dfc$active) OR
       ((p_cpu_queue_header^.partner_status.server_state = dfc$deactivated) AND
       allowed_when_server_deactivated AND NOT p_cpu_queue_header^.partner_status.deactivate_complete) OR
       ((p_cpu_queue_header^.partner_status.server_state = dfc$recovering) AND dfv$recovery_task) THEN
        osp$begin_subsystem_activity;
        subsystem_activity_began := TRUE;
        #SPOIL (subsystem_activity_began);
      ELSE
        dfp$set_terminated_status (p_queue_interface_table, queue_entry_loc_int.queue_index, status);
      IFEND;
      IF status.normal THEN
        dfp$get_task_queue_entry (p_queue_interface_table, queue_entry_loc_int.queue_index,
              queue_entry_loc_int.queue_entry_index, p_driver_queue_entry, p_cpu_queue_entry, status);
        IF status.normal THEN
          {  Construct pointer to  user part of send buffer area .
          syp$hang_if_job_jrt_set (dfc$tjr_begin_rpc);
          RESET p_cpu_queue_entry^.p_send_buffer;
          NEXT p_send_buffer_header IN p_cpu_queue_entry^.p_send_buffer;
          NEXT p_send_rpc_buffer_header IN p_cpu_queue_entry^.p_send_buffer;
          NEXT p_send_to_server_params IN p_cpu_queue_entry^.p_send_buffer;
          RESET p_send_to_server_params;
          RESET p_cpu_queue_entry^.p_send_data;
          p_send_data := p_cpu_queue_entry^.p_send_data;
          p_cpu_queue_entry^.maximum_data_sent := 0;
          p_cpu_queue_entry^.maximum_data_received := 0;
          pmp$get_executing_task_gtid (p_cpu_queue_entry^.global_task_id);
          dfp$convert_qel_int_to_ext (queue_entry_loc_int, queue_entry_location);
        ELSE
          osp$end_subsystem_activity;
          subsystem_activity_began := FALSE;
          #SPOIL (subsystem_activity_began);
        IFEND;
      IFEND;
    IFEND;

    IF status.normal THEN
      syp$push_inhibit_job_recovery;
      #KEYPOINT (osk$exit, osk$m * queue_entry_loc_int.queue_entry_index, dfk$begin_remote_procedure_call);
    ELSE
      #KEYPOINT (osk$exit, 0, dfk$begin_remote_procedure_call);
    IFEND;
  PROCEND dfp$begin_remote_procedure_call;
?? TITLE := ' [XDCL, #GATE] dfp$end_remote_procedure_call ', EJECT ??
*copyc dfh$end_remote_procedure_call

  PROCEDURE [XDCL, #GATE] dfp$end_remote_procedure_call
    (    queue_entry_location: dft$rpc_queue_entry_location;
     VAR status: ost$status);


    VAR
      caller_id: ost$caller_identifier,
      ignore_status: ost$status,
      p_cpu_queue_entry: ^dft$cpu_queue_entry,
      p_driver_queue_entry: ^dft$driver_queue_entry,
      p_queue_interface_table: dft$p_queue_interface_table,
      queue_entry_loc_int: dft$rpc_queue_entry_loc_int;

    status.normal := TRUE;
    dfp$convert_qel_ext_to_int (queue_entry_location, queue_entry_loc_int);
    #KEYPOINT (osk$entry, osk$m * queue_entry_loc_int.queue_entry_index, dfk$end_remote_procedure_call);
    #CALLER_ID (caller_id);
    IF caller_id.ring > osc$tsrv_ring THEN
      osp$set_status_abnormal ('PM', pme$insufficient_privilege, '', status);
      RETURN;
    IFEND;
    dfp$validate_queue_entry_loc (queue_entry_loc_int, 'dfp$end_remote_procedure_call',
          p_queue_interface_table, status);
    IF status.normal THEN

      dfp$fetch_queue_entry (p_queue_interface_table, queue_entry_loc_int.queue_index,
            queue_entry_loc_int.queue_entry_index, p_driver_queue_entry, p_cpu_queue_entry);

      end_remote_procedure_call (p_queue_interface_table, queue_entry_loc_int.queue_index,
              queue_entry_loc_int.queue_entry_index, p_cpu_queue_entry, status);
    ELSEIF (status.condition = dfe$server_has_terminated) OR
           (status.condition = dfe$server_not_active) THEN
      { The server has terminated since the time of the begin remote procedure call.
      { Allow the caller to continue and recover in this case.
      { Termination should have cleaned up any wired pages.
      syp$pop_inhibit_job_recovery;
      osp$end_subsystem_activity;
      status.normal := TRUE;
    IFEND;
    #KEYPOINT (osk$exit, 0, dfk$end_remote_procedure_call);

  PROCEND dfp$end_remote_procedure_call;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] dfp$find_extended_rpc_ordinal', EJECT ??

{ PURPOSE:
{   The purpose of this request is to return the RPC address list
{   ordinal of the specified remote application procedure.

  PROCEDURE [XDCL] dfp$find_extended_rpc_ordinal
    (    application_name: ost$name;
         procedure_name: pmt$program_name;
         p_cpu_queue: ^dft$cpu_queue;
     VAR extended_rpc_ordinal: dft$procedure_address_ordinal;
     VAR status: ost$status);

    VAR
      application_index: dft$number_of_applications,
      application_found: boolean,
      name_is_valid: boolean,
      procedure_found: boolean,
      procedure_index: dft$total_number_of_app_procs,
      procedure_index_offset: dft$total_number_of_app_procs,
      p_remote_application_info: ^dft$remote_application_info,
      valid_application_name: ost$name,
      valid_procedure_name: ost$name;

    status.normal := TRUE;

    application_index := 0;
    application_found := FALSE;
    procedure_found := FALSE;
    p_remote_application_info := p_cpu_queue^.queue_header.p_remote_application_info;

    clp$validate_name (application_name, valid_application_name, name_is_valid);
    IF NOT name_is_valid THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$application_not_known,
            application_name, status);
      RETURN;
    IFEND;

  /match_application_name/
    WHILE p_remote_application_info <> NIL DO
      application_index := application_index + 1;
      IF p_remote_application_info^.application_name = valid_application_name THEN
        application_found := TRUE;
        EXIT /match_application_name/;
      IFEND;
      p_remote_application_info := p_remote_application_info^.next_p_application_info;
    WHILEND /match_application_name/;

    IF NOT application_found THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$application_not_known,
            application_name, status);
      RETURN;
    IFEND;
    IF p_cpu_queue^.queue_header.p_application_rpc_list = NIL THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$procedure_not_known,
            procedure_name, status);
      osp$append_status_parameter (osc$status_parameter_delimiter, application_name, status);
      RETURN;
    IFEND;

    clp$validate_name (procedure_name, valid_procedure_name, name_is_valid);
    IF NOT name_is_valid THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$procedure_not_known,
            procedure_name, status);
      osp$append_status_parameter (osc$status_parameter_delimiter, application_name, status);
      RETURN;
    IFEND;
    extended_rpc_ordinal := p_remote_application_info^.first_procedure_rpc_ordinal;
    procedure_index_offset := $INTEGER (extended_rpc_ordinal) - $INTEGER (dfc$last_system_procedure);

  /match_procedure_name/
    FOR procedure_index := procedure_index_offset TO (procedure_index_offset +
          p_remote_application_info^.number_of_procedures - 1) DO
      IF p_cpu_queue^.queue_header.p_application_rpc_list^ [procedure_index].debug_display =
            valid_procedure_name THEN
        procedure_found := TRUE;
        EXIT /match_procedure_name/;
      IFEND;
      extended_rpc_ordinal := SUCC (extended_rpc_ordinal);
    FOREND /match_procedure_name/;
    IF NOT procedure_found THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$procedure_not_known,
            procedure_name, status);
      osp$append_status_parameter (osc$status_parameter_delimiter, application_name, status);
    IFEND;
  PROCEND dfp$find_extended_rpc_ordinal;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] dfp$send_application_rpc ', EJECT ??
*copy dfh$send_application_rpc

  PROCEDURE [XDCL, #GATE] dfp$send_application_rpc
    (    queue_entry_location: dft$rpc_queue_entry_location;
         application_name: ost$name;
         procedure_name: pmt$program_name;
         send_to_server_params_size: dft$send_parameter_size;
         data_size_to_send_to_server: dft$send_data_size;
     VAR p_receive_from_server_params: dft$p_receive_parameters;
     VAR p_receive_data: dft$p_receive_data;
     VAR status: ost$status);

    VAR
      p_cpu_queue: ^dft$cpu_queue,
      p_queue_interface_table: dft$p_queue_interface_table,
      procedure_ordinal: dft$procedure_address_ordinal,
      queue_entry_loc_int: dft$rpc_queue_entry_loc_int;

    dfp$convert_qel_ext_to_int (queue_entry_location, queue_entry_loc_int);
    dfp$validate_queue_entry_loc (queue_entry_loc_int, 'dfp$send_application_rpc', p_queue_interface_table,
          status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    p_cpu_queue := p_queue_interface_table^.queue_directory.
          cpu_queue_pva_directory [queue_entry_loc_int.queue_index].p_cpu_queue;

    dfp$find_extended_rpc_ordinal (application_name, procedure_name, p_cpu_queue, procedure_ordinal, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    dfp$send_remote_procedure_call (queue_entry_location, procedure_ordinal, send_to_server_params_size,
          data_size_to_send_to_server, p_receive_from_server_params, p_receive_data, status);

  PROCEND dfp$send_application_rpc;
?? TITLE := ' [XDCL, #GATE] dfp$send_remote_procedure_call ', EJECT ??
*copyc dfh$send_remote_procedure_call
?? EJECT ??

  PROCEDURE [XDCL, #GATE] dfp$send_remote_procedure_call
    (    queue_entry_location: dft$rpc_queue_entry_location;
         procedure_ordinal: dft$procedure_address_ordinal;
         send_to_server_params_size: dft$send_parameter_size;
         data_size_to_send_to_server: dft$send_data_size;
     VAR p_receive_from_server_params: dft$p_receive_parameters;
     VAR p_receive_data: dft$p_receive_data;
     VAR status: ost$status);


    PROCEDURE send_rpc_job_rec_cond_handler
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        display_string_length: integer,
        display_string: string (90),
        display_status: ost$status;

      IF (condition.selector = pmc$user_defined_condition) AND
            (condition.user_condition_name = 'OSC$JOB_RECOVERY') THEN
        osp$set_status_abnormal (dfc$file_server_id, dfe$server_not_active,
              ' job recovery rollback - send_rpc ', status);
        STRINGREP (display_string, display_string_length,
             ' Job recovery rollback dfp$send_remote_procedure_call ',
              current_rpc_entry.debug_display);
        osp$log_job_recovery_message (display_string (1, display_string_length),
              display_status);
        { Must push here since in the end_rpc will try to pop it.
        syp$push_inhibit_job_recovery;
        IF dfv$file_server_debug_enabled THEN
          display_trace_back;
        IFEND;
        EXIT dfp$send_remote_procedure_call;
      IFEND;

      pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);

    PROCEND send_rpc_job_rec_cond_handler;


    VAR
      allow_terminate_break: boolean,
      allow_pause_break: boolean,
      caller_id: ost$caller_identifier,
      client_job_id: dft$client_job_id,
      current_rpc_entry: dft$rpc_procedure_address_entry,
      p_cpu_queue_entry: ^dft$cpu_queue_entry,
      p_driver_queue_entry: ^dft$driver_queue_entry,
      p_queue_interface_table: dft$p_queue_interface_table,
      queue_entry_loc_int: dft$rpc_queue_entry_loc_int,
      recovery_condition_enabled: boolean;

    #KEYPOINT (osk$entry, osk$m * $INTEGER (procedure_ordinal), dfk$send_remote_procedure_call);
    IF (send_to_server_params_size > dfc$maximum_user_buffer_area) OR
          (send_to_server_params_size < 0) THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$out_of_range_value,
            'SEND_TO_SERVER_PARAMS_SIZE', status);
      osp$append_status_parameter (osc$status_parameter_delimiter,
            'passed to DFP$SEND_REMOTE_PROCEDURE_CALL',  status);
      osp$append_status_integer (osc$status_parameter_delimiter, send_to_server_params_size,
            10, FALSE, status);
      osp$append_status_integer (osc$status_parameter_delimiter, 0, 10, FALSE, status);
      osp$append_status_integer (osc$status_parameter_delimiter, dfc$maximum_user_buffer_area,
            10, FALSE, status);
      RETURN;
    IFEND;
    IF (data_size_to_send_to_server > dfc$maximum_user_data_area) OR
          (data_size_to_send_to_server < 0) THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$out_of_range_value,
           'DATA_SIZE_TO_SEND_TO_SERVER', status);
      osp$append_status_parameter (osc$status_parameter_delimiter,
            'passed to DFP$SEND_REMOTE_PROCEDURE_CALL',  status);
      osp$append_status_integer (osc$status_parameter_delimiter, data_size_to_send_to_server,
            10, FALSE, status);
      osp$append_status_integer (osc$status_parameter_delimiter, 0, 10, FALSE, status);
      osp$append_status_integer (osc$status_parameter_delimiter, dfc$maximum_user_data_area,
            10, FALSE, status);
      RETURN;
    IFEND;

    dfp$convert_qel_ext_to_int (queue_entry_location, queue_entry_loc_int);
    dfp$validate_queue_entry_loc (queue_entry_loc_int, 'dfp$send_remote_procedure_call',
          p_queue_interface_table, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    IF procedure_ordinal <= dfc$last_system_procedure THEN
      osp$verify_system_privilege;
      current_rpc_entry := dfv$procedure_address_list [procedure_ordinal];
      allow_terminate_break := FALSE;
      allow_pause_break := FALSE;
    ELSE
      #CALLER_ID (caller_id);
      IF caller_id.ring > osc$tsrv_ring THEN
        osp$set_status_abnormal ('PM', pme$insufficient_privilege, '', status);
        RETURN;
      IFEND;
      current_rpc_entry := p_queue_interface_table^.queue_directory.
            cpu_queue_pva_directory [queue_entry_loc_int.queue_index].p_cpu_queue^.queue_header.
            p_application_rpc_list^ [$INTEGER (procedure_ordinal) - $INTEGER (dfc$last_system_procedure)];
      allow_terminate_break := current_rpc_entry.allow_terminate_break;
      allow_pause_break := current_rpc_entry.allow_pause_break;
    IFEND;
    recovery_condition_enabled := FALSE;
    IF status.normal THEN
      dfp$fetch_queue_entry (p_queue_interface_table, queue_entry_loc_int.queue_index,
            queue_entry_loc_int.queue_entry_index, p_driver_queue_entry, p_cpu_queue_entry);
      IF (procedure_ordinal <> dfc$establish_client_job) AND
         (procedure_ordinal <> dfc$rpc_jl_general_purpose) AND
         (procedure_ordinal <> dfc$rpc_jl_terminate_job) THEN
        dfp$check_job_server (queue_entry_location, queue_entry_loc_int, send_to_server_params_size,
              (procedure_ordinal IN dfv$job_recovery_rpc_requests),
               { Force reconnecting = } FALSE, client_job_id, status);
        IF NOT status.normal AND (status.condition = dfe$job_needs_recovery) THEN
          CASE current_rpc_entry.job_recovery_location OF
          = dfc$job_rec_started_by_caller =
            { Return dfe$job_needs_recovery to allow the caller to initiate the recovery
            { at an appropriate place.
          = dfc$job_rec_in_unavailable_wait =
            { Return the status of dfe$server_not_active to allow the recovery
            { to be performed as a result of waiting for unavailable server.
            osp$set_status_condition (dfe$server_not_active, status);
          = dfc$job_rec_immediately =
            { This assumes that there is a spare queue entry, since the
            { dfp$recover_job will assign and release queue entries.  There
            { is the possibility of deadlock here.
            dfp$recover_job (queue_entry_loc_int.server_mainframe_id, status);
          ELSE
          CASEND;
        IFEND;
      IFEND;
    IFEND;

    IF status.normal THEN
      IF (current_rpc_entry.request_restartable =
            dfc$request_restartable) AND
         (procedure_ordinal <> dfc$change_job_validation_info) THEN
        { If the request is restartable we allow recovery to occur during this process.
        osp$establish_condition_handler (^send_rpc_job_rec_cond_handler, FALSE);
        syp$pop_inhibit_job_recovery;
        recovery_condition_enabled:= TRUE;
      IFEND;

    /repeat_request_on_retry/
      REPEAT
        IF NOT status.normal AND (status.condition = dfe$restart_server_request) AND
              dfv$file_server_debug_enabled THEN
          display_integer (' CLIENT RESTARTING REQUEST FOR ', queue_entry_loc_int.queue_entry_index);
        IFEND;
        send_remote_procedure_call (p_queue_interface_table, allow_terminate_break, allow_pause_break,
              queue_entry_loc_int.queue_index, queue_entry_loc_int.queue_entry_index, p_cpu_queue_entry,
              p_driver_queue_entry, client_job_id, procedure_ordinal, send_to_server_params_size,
              data_size_to_send_to_server, p_receive_from_server_params, p_receive_data, status);
        IF NOT status.normal AND (status.condition = dfe$bad_client_job_id) AND
           NOT (procedure_ordinal IN dfv$job_recovery_rpc_requests) THEN
          dfp$check_job_server (queue_entry_location, queue_entry_loc_int, send_to_server_params_size,
                (procedure_ordinal IN dfv$job_recovery_rpc_requests),
                 { Force reconnecting = } TRUE, client_job_id, status);
          IF status.normal THEN
            CYCLE /repeat_request_on_retry/;
          IFEND;
        IFEND;
      UNTIL status.normal OR (status.condition <> dfe$restart_server_request);
    IFEND;
    IF status.normal THEN
      IF data_size_to_send_to_server > p_cpu_queue_entry^.maximum_data_sent THEN
        p_cpu_queue_entry^.maximum_data_sent := data_size_to_send_to_server;
      IFEND;
      IF (p_receive_data <> NIL) AND (#SIZE (p_receive_data^) > p_cpu_queue_entry^.maximum_data_received) THEN
        p_cpu_queue_entry^.maximum_data_received := #SIZE (p_receive_data^);
      IFEND;
      IF procedure_ordinal = dfc$get_validation_info THEN
        dfp$set_job_validation_change;
      IFEND;
    IFEND;
    IF recovery_condition_enabled THEN
      syp$push_inhibit_job_recovery;
    IFEND;
    #KEYPOINT (osk$exit, 0, dfk$send_remote_procedure_call);

  PROCEND dfp$send_remote_procedure_call;
?? TITLE := ' [XDCL, INLINE] dfp$validate_queue_entry_loc ', EJECT ??

  PROCEDURE [XDCL,INLINE] dfp$validate_queue_entry_loc
    (    queue_entry_loc_int: dft$rpc_queue_entry_loc_int;
         request: string ( * <= osc$max_name_size);
     VAR p_queue_interface_table: dft$p_queue_interface_table;
     VAR status: ost$status);

    VAR
      global_task_id: ost$global_task_id,
      p_cpu_queue_entry: ^dft$cpu_queue_entry,
      p_driver_queue_entry: ^dft$driver_queue_entry,
      queue_entry_assigned: boolean;

    status.normal := TRUE;

    IF (dfv$p_queue_interface_directory = NIL) OR (queue_entry_loc_int.queue_directory_index >
          UPPERBOUND (dfv$p_queue_interface_directory^)) THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$server_has_terminated, 'Nil queue directory',
            status);
      RETURN;
    IFEND;
    dfp$get_qit_p_from_direct_index (queue_entry_loc_int.queue_directory_index, p_queue_interface_table);

    IF p_queue_interface_table^.queue_directory.cpu_queue_pva_directory [queue_entry_loc_int.queue_index].
          p_cpu_queue^.queue_header.destination_mainframe_id <> queue_entry_loc_int.server_mainframe_id THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$invalid_queue_entry_id, 'mismatched mainframe id',
            status);
      osp$append_status_parameter (osc$status_parameter_delimiter, request, status);
      RETURN;
    IFEND;

    { Give server terminated status precedence to free entry, since termination
    { will free all assigned queue entries.  This is also true in the
    { awaiting recovery state.
    IF (p_queue_interface_table^.queue_directory.cpu_queue_pva_directory [queue_entry_loc_int.queue_index].
          p_cpu_queue^.queue_header.partner_status.server_state = dfc$terminated) OR
          (p_queue_interface_table^.queue_directory.cpu_queue_pva_directory [queue_entry_loc_int.queue_index].
          p_cpu_queue^.queue_header.partner_status.server_state = dfc$awaiting_recovery) THEN
      dfp$set_terminated_status (p_queue_interface_table, queue_entry_loc_int.queue_index, status);
      RETURN;
    IFEND;

    dfp$check_queue_entry_assigned (queue_entry_loc_int.queue_entry_index,
          p_queue_interface_table^.queue_directory.cpu_queue_pva_directory [queue_entry_loc_int.queue_index].
          p_cpu_queue^.queue_header.queue_entry_assignment_table, queue_entry_assigned);
    IF queue_entry_assigned THEN
      dfp$fetch_queue_entry (p_queue_interface_table, queue_entry_loc_int.queue_index,
            queue_entry_loc_int.queue_entry_index, p_driver_queue_entry, p_cpu_queue_entry);
      pmp$get_executing_task_gtid (global_task_id);
      IF global_task_id <> p_cpu_queue_entry^.global_task_id THEN
        osp$set_status_abnormal (dfc$file_server_id, dfe$invalid_queue_entry_id, 'entry not assigned',
              status);
        osp$append_status_parameter (osc$status_parameter_delimiter, request, status);
        RETURN;
      IFEND;
    ELSE
      osp$set_status_abnormal (dfc$file_server_id, dfe$invalid_queue_entry_id, 'entry not assigned', status);
      osp$append_status_parameter (osc$status_parameter_delimiter, request, status);
      RETURN;
    IFEND;
  PROCEND dfp$validate_queue_entry_loc;
?? TITLE := ' end_remote_procedure_call', EJECT ??
  PROCEDURE end_remote_procedure_call
    (    p_queue_interface_table: dft$p_queue_interface_table;
         queue_index: dft$queue_index;
         queue_entry_index: dft$queue_entry_index;
         p_cpu_queue_entry: ^dft$cpu_queue_entry;
     VAR status: ost$status);

    VAR
      ignore_status: ost$status;

    status.normal := TRUE;
    IF p_cpu_queue_entry^.maximum_data_sent > 0 THEN
      mmp$free_pages (p_cpu_queue_entry^.p_send_data, p_cpu_queue_entry^.maximum_data_sent, osc$wait,
            ignore_status);
    IFEND;
    IF p_cpu_queue_entry^.maximum_data_received > 0 THEN
      mmp$free_pages (p_cpu_queue_entry^.p_receive_data, p_cpu_queue_entry^.maximum_data_received, osc$wait,
            ignore_status);
    IFEND;

    syp$hang_if_job_jrt_set (dfc$tjr_end_rpc);
    dfp$release_task_queue_entry (p_queue_interface_table, queue_index, queue_entry_index, status);
    syp$pop_inhibit_job_recovery;
    osp$end_subsystem_activity;

  PROCEND end_remote_procedure_call;
?? TITLE := ' initialize_rpc_send ', EJECT ??

{  This procedure initializes the standard send buffer, the remote procedure
{  call buffer header, and the cpu queue entry.
{

  PROCEDURE initialize_rpc_send
    (    client_job_id: dft$client_job_id;
         procedure_ordinal: dft$procedure_address_ordinal;
         p_cpu_queue_entry: ^dft$cpu_queue_entry;
         p_send_buffer_header: ^dft$buffer_header;
         p_send_rpc_buffer_header: ^dft$rpc_buffer_header;
         user_parameter_size: dft$send_parameter_size;
         data_size_to_send: dft$send_data_size;
         p_cpu_queue: ^dft$cpu_queue);

    VAR
      current_rpc_entry: dft$rpc_procedure_address_entry,
      ignore_status: ost$status,
      user_supplied_name: jmt$user_supplied_name;

    { Initialize standard buffer header
    p_send_buffer_header^.version := dfc$rpc_request_buffer_version;
    p_send_buffer_header^.remote_processor := procedure_ordinal;
    p_send_buffer_header^.data_length_sent := 0;

    { Initialize remote procedure call buffer header
    IF procedure_ordinal <= dfc$last_system_procedure THEN
      current_rpc_entry := dfv$procedure_address_list [procedure_ordinal];
    ELSE
      current_rpc_entry := p_cpu_queue^.queue_header.p_application_rpc_list^
            [$INTEGER (procedure_ordinal) - $INTEGER (dfc$last_system_procedure)];
    IFEND;
    pmp$get_job_names (user_supplied_name, p_send_rpc_buffer_header^.system_supplied_job_name, ignore_status);
    p_send_rpc_buffer_header^.procedure_version := current_rpc_entry.procedure_version;
    p_send_rpc_buffer_header^.procedure_name_checksum := current_rpc_entry.procedure_name_checksum;
    p_send_rpc_buffer_header^.procedure_class := current_rpc_entry.class;
    IF current_rpc_entry.class = dfc$permanent_file_call THEN
      p_send_rpc_buffer_header^.client_job_id := client_job_id;
      p_send_rpc_buffer_header^.system_administrator := avp$system_administrator ();
      p_send_rpc_buffer_header^.family_administrator := avp$family_administrator ();
    IFEND;

    { Initialize rpc progress record
    p_send_rpc_buffer_header^.call_progress.transaction_per_rpc_request := 0;
    p_send_rpc_buffer_header^.call_progress.total_data_sent := 0;
    p_send_rpc_buffer_header^.call_progress.total_data_received := 0;

    p_send_rpc_buffer_header^.call_progress.user_buffer_length_sent := user_parameter_size;
    p_send_rpc_buffer_header^.call_progress.user_data_length_sent := data_size_to_send;

    { Initialize cpu queue entry
    p_cpu_queue_entry^.call_progress := p_send_rpc_buffer_header^.call_progress;
    p_cpu_queue_entry^.total_data_to_receive := 0;
  PROCEND initialize_rpc_send;
?? TITLE := ' locate_server ', EJECT ??
{
{  This procedure locates the server mainframe, and initializes the queue
{  entry location.  The queue entry index field is not initialized by this
{  procedure.
{

  PROCEDURE locate_server
    (    server_location: dft$server_location;
     VAR p_queue_interface_table: dft$p_queue_interface_table;
     VAR queue_entry_loc_int: dft$rpc_queue_entry_loc_int;
     VAR status: ost$status);

    VAR
      family: ost$family_name,
      family_found: boolean,
      mainframe_found: boolean,
      p_cpu_queue: ^dft$cpu_queue,
      p_q_interface_directory_entry: ^dft$q_interface_directory_entry,
      served_family_table_index: dft$served_family_table_index,
      server_state: dft$server_state,
      server_to_client: boolean;

    status.normal := TRUE;
    CASE server_location.server_location_selector OF
    = dfc$family_name =
      dfp$locate_served_family (server_location.family_name, family_found, served_family_table_index,
            queue_entry_loc_int.server_mainframe_id, p_queue_interface_table, queue_entry_loc_int.queue_index,
            server_state);
      IF NOT family_found THEN
        osp$set_status_abnormal (dfc$file_server_id, dfe$family_not_served, server_location.family_name,
              status);
        RETURN;
      IFEND;
      IF (p_queue_interface_table = NIL) THEN
        { Access to a recovering server is occuring prior to the definition of the server.
        { Determine the state of the server.
        dfp$fetch_served_family_state  (served_family_table_index, server_state);
        IF server_state = dfc$awaiting_recovery THEN
         { Return the status of dfe$server_not_active to allow the recovery
         { to be performed as a result of waiting for unavailable server.
           osp$set_status_abnormal (dfc$file_server_id,
              dfe$server_not_active, server_location.family_name, status);
         ELSE
           osp$set_status_abnormal (dfc$file_server_id,
              dfe$server_has_terminated, server_location.family_name, status);
        IFEND;
      IFEND;
    = dfc$mainframe_id =
      server_to_client := FALSE;
      dfp$find_mainframe_id (server_location.server_mainframe, server_to_client, mainframe_found,
            p_queue_interface_table, p_cpu_queue, queue_entry_loc_int.queue_index,
            p_q_interface_directory_entry);
      IF mainframe_found THEN
        queue_entry_loc_int.server_mainframe_id := p_cpu_queue^.queue_header.destination_mainframe_id;
      ELSE
        osp$set_status_abnormal (dfc$file_server_id, dfe$mainframe_not_server,
              server_location.server_mainframe, status);
      IFEND;

    = dfc$served_family_table_index =
      osp$verify_system_privilege;
      dfp$fetch_served_family_info (server_location.served_family_table_index, family,
            queue_entry_loc_int.server_mainframe_id, p_queue_interface_table, queue_entry_loc_int.queue_index,
            family_found);
      IF NOT family_found THEN
        dfp$set_invalid_family_index (server_location.served_family_table_index,
              'DFP$BEGIN_REMOTE_PROCEDURE_CALL', status);
        RETURN;
      IFEND;
      dfp$fetch_served_family_state  (server_location.served_family_table_index, server_state);
      IF (p_queue_interface_table = NIL) OR (server_state = dfc$deleted) THEN
        { Access to a recovering server is occuring prior to the definition of the server.
        { Determine the state of the server.
        IF server_state = dfc$awaiting_recovery THEN
         { Return the status of dfe$server_not_active to allow the recovery
         { to be performed as a result of waiting for unavailable server.
           osp$set_status_abnormal (dfc$file_server_id,
              dfe$server_not_active, family, status);
         ELSE
           osp$set_status_abnormal (dfc$file_server_id,
              dfe$server_has_terminated, family, status);
        IFEND;
        RETURN;
      IFEND;

    ELSE
      osp$set_status_abnormal (dfc$file_server_id, dfe$invalid_server_locator, '', status);
    CASEND;

    IF status.normal THEN
      { This is a temporary kludge until queue directory index is added to
      { Served family table, and returned by the above interfaces.
      { With only one server this interface is not to slow.
      dfp$get_queue_directory_index (p_queue_interface_table, queue_entry_loc_int.queue_directory_index);
    IFEND;
  PROCEND locate_server;
?? TITLE := ' receive_data_from_server ', EJECT ??
{
{   This procedure makes repeated requests to the server to receive
{ any data that is being sent. IF no data was sent to the server, the
{ initial
{ four pages of data is prompted for.  After the initial data is received,
{ the remaining data is received with a new request. The user part of the
{ buffer area is not received until the last data pages are received.
{

  PROCEDURE receive_data_from_server
    (    p_queue_interface_table: dft$p_queue_interface_table;
         queue_index: dft$queue_index;
         queue_entry_index: dft$queue_entry_index;
         p_cpu_queue_entry: ^dft$cpu_queue_entry;
         p_driver_queue_entry: ^dft$driver_queue_entry;
         p_send_buffer_header: ^dft$buffer_header;
         p_send_rpc_buffer_header: ^dft$rpc_buffer_header;
     VAR p_receive_rpc_buffer_header: ^dft$rpc_response_buffer_header;
     VAR p_receive_data: dft$p_receive_data;
     VAR status: ost$status);

    VAR
      data_received_this_request: dft$send_data_size,
      p_mtr_status: ^syt$monitor_status,
      p_os_status: ^ost$status,
      p_receive_buffer_header: ^dft$buffer_header,
      page_count: ost$non_negative_integers,
      remaining_data_to_receive: dft$send_data_size;

    status.normal := TRUE;
    RESET p_cpu_queue_entry^.p_receive_buffer;
    NEXT p_receive_buffer_header IN p_cpu_queue_entry^.p_receive_buffer;
    NEXT p_mtr_status IN p_cpu_queue_entry^.p_receive_buffer;

    remaining_data_to_receive := p_cpu_queue_entry^.total_data_to_receive;

    dfp$touch_pages (p_cpu_queue_entry^.p_receive_data, p_cpu_queue_entry^.total_data_to_receive, page_count);

    IF (p_cpu_queue_entry^.call_progress.total_data_sent = 0) THEN
      {No data was sent with the request, prompt for the initial data from esm.
      IF remaining_data_to_receive > p_queue_interface_table^.maximum_data_bytes THEN
        { All the data won't fit in this request
        data_received_this_request := p_queue_interface_table^.maximum_data_bytes;
        remaining_data_to_receive := remaining_data_to_receive - data_received_this_request;
      ELSE { Last receive request
        data_received_this_request := remaining_data_to_receive;
        remaining_data_to_receive := 0;
      IFEND;
      dfp$initialize_rma_list (p_cpu_queue_entry^.p_receive_data, { Offset = } 0, data_received_this_request,
            p_cpu_queue_entry^.p_data_rma_list, p_driver_queue_entry^.data_descriptor, status);
      p_driver_queue_entry^.flags := dfv$send_ready_for_data_flags;
      #SPOIL (p_driver_queue_entry^);
      dfp$queue_client_task_request (p_queue_interface_table, queue_index, queue_entry_index, status);
      IF NOT status.normal THEN
        dfp$clear_driver_flags (p_driver_queue_entry);
        RETURN;
      IFEND;
      #SPOIL (p_driver_queue_entry^);
      dfp$await_subsystem_action (p_driver_queue_entry);
      p_cpu_queue_entry^.call_progress.total_data_received :=
            (p_driver_queue_entry^.data_descriptor.actual_length DIV 8) * osv$page_size;
      dfp$clear_driver_flags (p_driver_queue_entry);
      NEXT p_receive_rpc_buffer_header IN p_cpu_queue_entry^.p_receive_buffer;
    IFEND;

{ Receive any remaining data by a new request
    p_send_buffer_header^.buffer_length_sent := dfp$word_boundary
          (#SIZE (dft$buffer_header) + #SIZE (dft$rpc_buffer_header));
    p_send_buffer_header^.data_length_sent := 0;
    p_driver_queue_entry^.send_buffer_descriptor.actual_length := p_send_buffer_header^.buffer_length_sent;

  /receive_all_data/
    WHILE (remaining_data_to_receive > 0) AND (status.normal) DO
      IF remaining_data_to_receive > p_queue_interface_table^.maximum_data_bytes THEN
        { All the data won't fit in this request
        data_received_this_request := p_queue_interface_table^.maximum_data_bytes;
        remaining_data_to_receive := remaining_data_to_receive - data_received_this_request;

      ELSE { Last receive request
        data_received_this_request := remaining_data_to_receive;
        remaining_data_to_receive := 0;
      IFEND;
      dfp$initialize_rma_list (p_cpu_queue_entry^.p_receive_data,
            { Offset = } p_cpu_queue_entry^.call_progress.total_data_received, data_received_this_request,
            p_cpu_queue_entry^.p_data_rma_list, p_driver_queue_entry^.data_descriptor, status);

      { Initialize cpu queue entry
      p_cpu_queue_entry^.retransmission_count := 0;
      p_cpu_queue_entry^.transaction_count := p_cpu_queue_entry^.transaction_count + 1;
      p_send_buffer_header^.transaction_count := p_cpu_queue_entry^.transaction_count;
      p_cpu_queue_entry^.call_progress.transaction_per_rpc_request :=
            p_cpu_queue_entry^.call_progress.transaction_per_rpc_request + 1;
      { Initialize rpc progress record
      p_send_rpc_buffer_header^.call_progress := p_cpu_queue_entry^.call_progress;

      p_driver_queue_entry^.flags := dfv$send_command_flags;
      #SPOIL (p_driver_queue_entry^);
      #SPOIL (p_cpu_queue_entry^);
      dfp$queue_client_task_request (p_queue_interface_table, queue_index, queue_entry_index, status);
      IF NOT status.normal THEN
        dfp$clear_driver_flags (p_driver_queue_entry);
        RETURN;
      IFEND;
      #SPOIL (p_driver_queue_entry^);
      #SPOIL (p_cpu_queue_entry^);
      dfp$await_subsystem_action (p_driver_queue_entry);
      #SPOIL (p_driver_queue_entry^);
      #SPOIL (p_cpu_queue_entry^);
      dfp$validate_rpc_status (p_cpu_queue_entry, p_receive_rpc_buffer_header, status);
      IF NOT status.normal THEN
        dfp$clear_driver_flags (p_driver_queue_entry);
        RETURN;
      IFEND;
      p_cpu_queue_entry^.call_progress.total_data_received :=
            ((p_driver_queue_entry^.data_descriptor.actual_length DIV 8) * osv$page_size) +
            p_cpu_queue_entry^.call_progress.total_data_received;
      dfp$clear_driver_flags (p_driver_queue_entry);
    WHILEND /receive_all_data/;

    {  Build pointer to p_receive_data
    RESET p_cpu_queue_entry^.p_receive_data;
    NEXT p_receive_data: [[REP p_receive_rpc_buffer_header^.call_progress.user_data_length_sent OF cell]] IN
          p_cpu_queue_entry^.p_receive_data;

  PROCEND receive_data_from_server;
?? TITLE := ' send_remote_procedure_call ', EJECT ??

  PROCEDURE send_remote_procedure_call
    (    p_queue_interface_table: dft$p_queue_interface_table;
         allow_terminate_break: boolean;
         allow_pause_break: boolean;
         queue_index: dft$queue_index;
         queue_entry_index: dft$queue_entry_index;
         p_cpu_queue_entry: ^dft$cpu_queue_entry;
         p_driver_queue_entry: ^dft$driver_queue_entry;
         client_job_id: dft$client_job_id;
         procedure_ordinal: dft$procedure_address_ordinal;
         send_to_server_params_size: dft$send_parameter_size;
         data_size_to_send_to_server: dft$send_data_size;
     VAR p_receive_from_server_params: dft$p_receive_parameters;
     VAR p_receive_data: dft$p_receive_data;
     VAR status: ost$status);

    VAR
      p_receive_rpc_buffer_header: ^dft$rpc_response_buffer_header,
      p_send_buffer_header: ^dft$buffer_header,
      p_send_rpc_buffer_header: ^dft$rpc_buffer_header;

    p_receive_from_server_params := NIL;
    p_receive_data := NIL;
    RESET p_cpu_queue_entry^.p_send_buffer;
    NEXT p_send_buffer_header IN p_cpu_queue_entry^.p_send_buffer;
    NEXT p_send_rpc_buffer_header IN p_cpu_queue_entry^.p_send_buffer;
    initialize_rpc_send (client_job_id, procedure_ordinal, p_cpu_queue_entry, p_send_buffer_header,
          p_send_rpc_buffer_header, send_to_server_params_size, data_size_to_send_to_server,
          p_queue_interface_table^.queue_directory.cpu_queue_pva_directory [queue_index].p_cpu_queue);
    send_request_to_server (p_queue_interface_table, allow_terminate_break, allow_pause_break, queue_index,
          queue_entry_index, p_cpu_queue_entry, p_driver_queue_entry, send_to_server_params_size,
          data_size_to_send_to_server, p_send_buffer_header, p_send_rpc_buffer_header,
          p_receive_rpc_buffer_header, status);
    IF status.normal THEN
      IF (p_cpu_queue_entry^.total_data_to_receive > 0) THEN
        receive_data_from_server (p_queue_interface_table, queue_index, queue_entry_index, p_cpu_queue_entry,
              p_driver_queue_entry, p_send_buffer_header, p_send_rpc_buffer_header,
              p_receive_rpc_buffer_header, p_receive_data, status);
      IFEND;
      IF status.normal THEN
        IF p_receive_rpc_buffer_header^.call_progress.user_buffer_length_sent > 0 THEN
          NEXT p_receive_from_server_params: [[REP p_receive_rpc_buffer_header^.call_progress.
                user_buffer_length_sent OF cell]] IN p_cpu_queue_entry^.p_receive_buffer;
        IFEND;
      IFEND;
    IFEND;
  PROCEND send_remote_procedure_call;
?? TITLE := ' send_request_to_server ', EJECT ??

{  This procedure sends the data and buffer over to the server.  If
{  multiple requests are needed to send the data, the portion of the
{  buffer with the user parameters is not sent over till the last
{  request. Each 4 page request is a new transaction.

  PROCEDURE send_request_to_server
    (    p_queue_interface_table: dft$p_queue_interface_table;
         allow_terminate_break: boolean;
         allow_pause_break: boolean;
         queue_index: dft$queue_index;
         queue_entry_index: dft$queue_entry_index;
         p_cpu_queue_entry: ^dft$cpu_queue_entry;
         p_driver_queue_entry: ^dft$driver_queue_entry;
         send_to_server_params_size: dft$send_parameter_size;
         data_size_to_send_to_server: dft$send_data_size;
         p_send_buffer_header: ^dft$buffer_header;
         p_send_rpc_buffer_header: ^dft$rpc_buffer_header;
     VAR p_receive_rpc_buffer_header: ^dft$rpc_response_buffer_header;
     VAR status: ost$status);

    VAR
      data_send_this_request: dft$send_data_size,
      p_status_response: ^dft$status_response;

  /send_all_data/
    REPEAT

      { Determine amount of data to send.
      IF data_size_to_send_to_server = 0 THEN
        data_send_this_request := 0;
        p_driver_queue_entry^.data_descriptor.actual_length := 0;
        p_send_buffer_header^.data_length_sent := 0;
        p_send_buffer_header^.buffer_length_sent := dfp$word_boundary
              (#SIZE (dft$buffer_header) + #SIZE (dft$rpc_buffer_header) + send_to_server_params_size);
      ELSE {Data to send to server
        IF (data_size_to_send_to_server - p_cpu_queue_entry^.call_progress.total_data_sent) >
            p_queue_interface_table^.maximum_data_bytes THEN
          { All the data won't fit in this request
          data_send_this_request := p_queue_interface_table^.maximum_data_bytes;
          p_send_buffer_header^.buffer_length_sent := dfp$word_boundary
                (#SIZE (dft$buffer_header) + #SIZE (dft$rpc_buffer_header));
        ELSE { Last send request
          { Only send all of the parameters over with the final piece of data
          data_send_this_request := data_size_to_send_to_server -
                p_cpu_queue_entry^.call_progress.total_data_sent;
          p_send_buffer_header^.buffer_length_sent := dfp$word_boundary
                (#SIZE (dft$buffer_header) + #SIZE (dft$rpc_buffer_header) + send_to_server_params_size);
        IFEND;
        dfp$initialize_rma_list (p_cpu_queue_entry^.p_send_data,
              {offset = } p_cpu_queue_entry^.call_progress.total_data_sent, data_send_this_request,
              p_cpu_queue_entry^.p_data_rma_list, p_driver_queue_entry^.data_descriptor, status);
        IF NOT status.normal THEN
          { User has not touched all of the pages.
          RETURN;
        IFEND;
        p_send_buffer_header^.data_length_sent := (p_driver_queue_entry^.data_descriptor.actual_length DIV
              8) * osv$page_size;
        p_cpu_queue_entry^.call_progress.total_data_sent :=
              p_cpu_queue_entry^.call_progress.total_data_sent + p_send_buffer_header^.data_length_sent;
      IFEND;

      { Initialize cpu queue entry
      p_cpu_queue_entry^.retransmission_count := 0;
      p_cpu_queue_entry^.transaction_count := p_cpu_queue_entry^.transaction_count + 1;
      { Update call progress
      p_cpu_queue_entry^.call_progress.transaction_per_rpc_request :=
            p_cpu_queue_entry^.call_progress.transaction_per_rpc_request + 1;

      { Complete initialization standard buffer header
      p_send_buffer_header^.transaction_count := p_cpu_queue_entry^.transaction_count;
      p_send_buffer_header^.retransmission_count := 0;
      { Complete Initialization  Remote procedure call header
      p_send_rpc_buffer_header^.call_progress := p_cpu_queue_entry^.call_progress;

      p_driver_queue_entry^.send_buffer_descriptor.actual_length := p_send_buffer_header^.buffer_length_sent;
      { Set up driver flags
      IF p_send_buffer_header^.data_length_sent > 0 THEN
        p_driver_queue_entry^.flags := dfv$send_command_and_data_flags;
      ELSE
        p_driver_queue_entry^.flags := dfv$send_command_flags;
      IFEND;
      dfp$queue_client_task_request (p_queue_interface_table, queue_index, queue_entry_index, status);
      syp$hang_if_job_jrt_set (dfc$tjr_send_rpc);
      IF NOT status.normal THEN
        dfp$clear_driver_flags (p_driver_queue_entry);
        RETURN;
      IFEND;

      IF (allow_terminate_break) OR (allow_pause_break) THEN
        wait_for_application_action (p_queue_interface_table, queue_index, queue_entry_index,
              p_cpu_queue_entry, p_driver_queue_entry, status);
        IF NOT status.normal THEN {cant establish condition handler
          dfp$await_subsystem_action (p_driver_queue_entry);
        IFEND;
        status.normal := TRUE;
      ELSE
        dfp$await_subsystem_action (p_driver_queue_entry);
      IFEND;
      dfp$clear_driver_flags (p_driver_queue_entry);
      dfp$validate_rpc_status (p_cpu_queue_entry, p_receive_rpc_buffer_header, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      p_cpu_queue_entry^.total_data_to_receive := p_receive_rpc_buffer_header^.call_progress.
            user_data_length_sent;

    UNTIL (p_cpu_queue_entry^.call_progress.total_data_sent >= data_size_to_send_to_server);
  PROCEND send_request_to_server;
?? OLDTITLE ??
?? NEWTITLE := 'send_pause_break', EJECT ??

{ PURPOSE:
{   The purpose of this request is to send a pause break inquiry
{   message to the server.

  PROCEDURE send_pause_break
    (    p_queue_interface_table: dft$p_queue_interface_table;
         queue_index: dft$queue_index;
         queue_entry_index: dft$queue_entry_index;
         p_cpu_queue_entry: ^dft$cpu_queue_entry);

    VAR
      ignore_queue_request_status: dft$queue_request_status,
      ignore_status: ost$status,
      inquiry_message: dft$inquiry_message,
      inquiry_tracer: dft$inquiry_tracer;

    dfp$form_inquiry_tracer (p_cpu_queue_entry^.transaction_count, p_cpu_queue_entry^.retransmission_count,
          inquiry_tracer);
    inquiry_message.transaction_state := dfc$pause_break_signal;
    inquiry_message.inquiry_tracer := inquiry_tracer;
    ofp$display_status_message (' Sending pause break to server', ignore_status);
    dfp$queue_inquiry_request (p_queue_interface_table, queue_index, queue_entry_index, inquiry_message,
          ignore_queue_request_status);

  PROCEND send_pause_break;

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

{ PURPOSE:
{   The purpose of this request is to send a terminate break inquiry
{   message to the server.

  PROCEDURE send_terminate_break
    (    p_queue_interface_table: dft$p_queue_interface_table;
         queue_index: dft$queue_index;
         queue_entry_index: dft$queue_entry_index;
         p_cpu_queue_entry: ^dft$cpu_queue_entry);

    VAR
      ignore_queue_request_status: dft$queue_request_status,
      ignore_status: ost$status,
      inquiry_message: dft$inquiry_message,
      inquiry_tracer: dft$inquiry_tracer;

    dfp$form_inquiry_tracer (p_cpu_queue_entry^.transaction_count, p_cpu_queue_entry^.retransmission_count,
          inquiry_tracer);
    inquiry_message.transaction_state := dfc$terminate_break_signal;
    inquiry_message.inquiry_tracer := inquiry_tracer;
    ofp$display_status_message (' Sending terminate break to server', ignore_status);
    dfp$queue_inquiry_request (p_queue_interface_table, queue_index, queue_entry_index, inquiry_message,
          ignore_queue_request_status);

  PROCEND send_terminate_break;

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

{ PURPOSE:
{   The purpose of this request is to allow a terminate_break condition or a pause_break condition
{   while waiting for the server to respond.

  PROCEDURE wait_for_application_action
    (    p_queue_interface_table: dft$p_queue_interface_table;
         queue_index: dft$queue_index;
         queue_entry_index: dft$queue_entry_index;
         p_cpu_queue_entry: ^dft$cpu_queue_entry;
         p_driver_queue_entry: ^dft$driver_queue_entry;
     VAR status: ost$status);

    VAR
      established_conditions: pmt$condition,
      established_descriptor: pmt$established_handler,
      ignore_status: ost$status;

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

{ PURPOSE:
{   The purpose of this request is to trap specified conditions and to
{   relay a terminate request or a pause request to the server.

    PROCEDURE condition_handler
      (    condition: pmt$condition;
           condition_descriptor: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      CASE condition.selector OF
      = ifc$interactive_condition =
        IF condition.interactive_condition = ifc$terminate_break THEN
          send_terminate_break (p_queue_interface_table, queue_index, queue_entry_index, p_cpu_queue_entry);
        ELSEIF condition.interactive_condition = ifc$pause_break THEN
          send_pause_break (p_queue_interface_table, queue_index, queue_entry_index, p_cpu_queue_entry);
        ELSE
          pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
        IFEND;
      = pmc$block_exit_processing =
        IF condition.reason <> $pmt$block_exit_reason [pmc$block_exit] THEN
          send_terminate_break (p_queue_interface_table, queue_index, queue_entry_index,
                p_cpu_queue_entry);
          REPEAT
            #SPOIL (p_driver_queue_entry^);
            pmp$delay (100, status);
            #SPOIL (p_driver_queue_entry^);
          UNTIL p_driver_queue_entry^.flags.subsystem_action;
         ofp$display_status_message ('  ', ignore_status);

          dfp$clear_driver_flags (p_driver_queue_entry);
          end_remote_procedure_call (p_queue_interface_table, queue_index, queue_entry_index,
                p_cpu_queue_entry, status);
        ELSE
          pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
        IFEND;
      ELSE
        pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
      CASEND;
    PROCEND condition_handler;
?? OLDTITLE ??

    established_conditions.selector := pmc$condition_combination;
    established_conditions.combination := $pmt$condition_combination
          [ifc$interactive_condition, pmc$block_exit_processing];
    pmp$establish_condition_handler (established_conditions, ^condition_handler,
          ^established_descriptor, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    REPEAT
      #SPOIL (p_driver_queue_entry^);
      pmp$long_term_wait (100, 100);
      #SPOIL (p_driver_queue_entry^);
    UNTIL p_driver_queue_entry^.flags.subsystem_action;

    pmp$disestablish_cond_handler (established_conditions, ignore_status);

  PROCEND wait_for_application_action;

MODEND dfm$client_remote_procedur_call;
