?? RIGHT := 110 ??
?? NEWTITLE := ' NOS/VE File Server: Client', EJECT ??
MODULE dfm$timeout_requests_to_server;

{ PURPOSE:
{   The purpose of this module is to process the outstanding requests
{         for a server mainframe being timed out.
{

?? NEWTITLE := '   Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc dfc$poll_constants
*copyc dfd$driver_queue_types
*copyc dfd$request_package
*copyc dfe$error_condition_codes
*copyc dfi$display
*copyc dfi$log_display
*copyc dft$cpu_queue
*copyc dft$page_io_request
*copyc dft$rb_file_server_request
*copyc dft$rpc_buffer_header
*copyc dfv$procedure_address_list
*copyc iot$pp_interface_table
*copyc pmt$task_status
*copyc syt$monitor_status
?? POP ??
*copyc dfp$check_queue_entry_assigned
*copyc dfp$find_mainframe_id
*copyc dfp$free_entry_assignment
*copyc dfp$locate_server_translation
*copyc dfv$file_server_debug_enabled
*copyc i#call_monitor
*copyc osp$append_status_parameter
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc osp$system_error
*copyc pmp$convert_binary_unique_name
*copyc pmp$wait
?? EJECT ??

?? TITLE := '    [XDCL] dfp$timeout_requests_to_server', EJECT ??

{
{   The purpose of this routine is to:
{  - Take care of queued requests:
{    Monitor requests are treated as an inactive server
{    Task requests are checked to determine if the server may have seen them
{      or if they are restartable requests.
{  - Change both active and swapped jobs so that they will wait for files
{      for this mainframe.
{  - Change the state of all server files to be awaiting recovery.
{

  PROCEDURE [XDCL] dfp$timeout_requests_to_server
    (    mainframe_name: pmt$mainframe_id;
     VAR status: ost$status);

    VAR
      gfn_name: ost$name,
      ignore_status: ost$status,
      mainframe_found: boolean,
      mainframe_ordinal: 1 .. dfc$max_number_of_mainframes,
      message: string (80),
      message_length: integer,
      p_cpu_queue: ^dft$cpu_queue,
      p_cpu_queue_entry: ^dft$cpu_queue_entry,
      p_driver_queue: ^dft$driver_queue,
      p_driver_queue_entry: ^dft$driver_queue_entry,
      p_ost_status: ^ost$status,
      p_page_io_request: ^dft$page_io_request,
      p_queue_interface_table: dft$p_queue_interface_table,
      p_q_interface_directory_entry: ^dft$q_interface_directory_entry,
      p_rpc_buffer_header: ^dft$rpc_buffer_header,
      p_send_buffer_header: ^dft$buffer_header,
      p_status_response: ^dft$status_response,
      queued_requests: 0 .. dfc$max_queue_entries,
      queue_entry_assigned: boolean,
      queue_index: dft$queue_index,
      q_d_index: dft$queue_directory_index,
      queue_entry_index: dft$queue_entry_index,
      request_block: dft$rb_file_server_request,
      request_status: ost$status,
      response_buffer_entry: dft$fs_pp_response,
      terminated_requests: 0 .. dfc$max_queue_entries,
      total_queue_entries: dft$queue_entry_index;

    status.normal := TRUE;
    queued_requests := 0;
    terminated_requests := 0;
    dfp$find_mainframe_id (mainframe_name, {host_is_server_to_client =} FALSE, mainframe_found,
          p_queue_interface_table, p_cpu_queue, queue_index, p_q_interface_directory_entry);
    IF NOT mainframe_found THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$mainframe_not_server, mainframe_name, status);
      RETURN;
    IFEND;

    p_driver_queue := p_queue_interface_table^.queue_directory.driver_queue_pva_directory [queue_index].
          p_driver_queue;
    p_driver_queue^.queue_header.flags.idle := TRUE;
    pmp$wait (2000, 2000);

    total_queue_entries := p_driver_queue^.queue_header.number_of_queue_entries;

{Search queues for active entry and determine what to do.

    request_block.reqcode := syc$rc_file_server_request;
    request_block.request := dfc$fsr_term_client_tasks;
    request_block.queue_interface_table_p := p_queue_interface_table;
    response_buffer_entry.response_flags.special_response := TRUE;
    response_buffer_entry.response_flags.one_word_response := TRUE;
    response_buffer_entry.response_flags.error_response := FALSE;
    response_buffer_entry.response_flags.inquiry_response := FALSE;
    response_buffer_entry.response_flags.termination_pseudo_response := TRUE;
    response_buffer_entry.response_length := 8 {bytes = 1 word} ;
    response_buffer_entry.logical_unit := 0; {Not used by dfp$process_server_response_a
    response_buffer_entry.queue_index := queue_index;

  /search_for_incomplete_actions/
    FOR queue_entry_index := dfc$poll_queue_index + 1 TO total_queue_entries DO
      dfp$check_queue_entry_assigned (queue_entry_index, p_cpu_queue^.queue_header.
            queue_entry_assignment_table, queue_entry_assigned);
      IF NOT queue_entry_assigned THEN
        CYCLE /search_for_incomplete_actions/;
      IFEND;
      queued_requests := queued_requests + 1;
      p_driver_queue_entry := ^p_driver_queue^.queue_entries [queue_entry_index];
      p_cpu_queue_entry := ^p_cpu_queue^.queue_entries [queue_entry_index];
      RESET p_cpu_queue_entry^.p_send_buffer;
      NEXT p_send_buffer_header IN p_cpu_queue_entry^.p_send_buffer;

{ Determine what to do with the outstanding request

      IF p_cpu_queue_entry^.processor_type = dfc$task_services THEN
        NEXT p_rpc_buffer_header IN p_cpu_queue_entry^.p_send_buffer;
        determine_queued_request_action (p_send_buffer_header^.remote_processor, p_rpc_buffer_header^,
              p_cpu_queue_entry, p_driver_queue_entry, mainframe_name, p_cpu_queue, request_status);
        IF request_status.normal THEN
          CYCLE /search_for_incomplete_actions/;
        IFEND;
      ELSE { For monitor entries force a wait
        osp$set_status_condition (dfe$server_not_active, request_status);
        IF dfv$file_server_debug_enabled THEN
          NEXT p_page_io_request IN p_cpu_queue_entry^.p_send_buffer;
          pmp$convert_binary_unique_name (p_page_io_request^.global_file_name, gfn_name, status);
          STRINGREP (message, message_length, ' qei', queue_entry_index,
            ' gfn', gfn_name, ' off', p_page_io_request^.segment_offset);
          display (message (1, message_length));
          log_display ($pmt$ascii_logset[pmc$system_log], message (1, message_length));
        IFEND;
      IFEND;
      response_buffer_entry.queue_entry_index := queue_entry_index;
      request_block.one_word_response := response_buffer_entry;
      RESET p_cpu_queue_entry^.p_receive_buffer;
      NEXT p_status_response IN p_cpu_queue_entry^.p_receive_buffer;
      p_status_response^.buffer_header.transaction_count := p_cpu_queue_entry^.transaction_count;
      p_status_response^.buffer_header.version := dfc$status_buffer_version;
      p_status_response^.buffer_header.remote_processor := p_send_buffer_header^.remote_processor;

{!! Assumming that the value returned is the same

      p_status_response^.status.normal := FALSE;
      p_status_response^.status.condition := request_status.condition;
      IF p_cpu_queue_entry^.processor_type = dfc$task_services THEN
        NEXT p_ost_status IN p_cpu_queue_entry^.p_receive_buffer;
        p_ost_status^ := request_status;
        IF request_status.condition = dfe$server_request_terminated THEN
          terminated_requests := terminated_requests + 1;
        IFEND;
      IFEND;
      request_block.cpu_queue_entry_p := p_cpu_queue_entry;
      request_block.status.normal := TRUE;
      p_driver_queue^.queue_entries [queue_entry_index].flags.active_entry := TRUE;
      p_driver_queue^.queue_entries [queue_entry_index].flags.driver_action := FALSE;
      p_driver_queue^.queue_entries [queue_entry_index].flags.subsystem_action := FALSE;
      p_driver_queue^.queue_entries [queue_entry_index].flags.buffer_received := TRUE;
      p_driver_queue^.queue_entries [queue_entry_index].flags.process_response := TRUE;

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

      IF NOT request_block.status.normal THEN

{  check if still assigned

        dfp$check_queue_entry_assigned (queue_entry_index, p_cpu_queue^.queue_header.
              queue_entry_assignment_table, queue_entry_assigned);
        IF queue_entry_assigned THEN
          dfp$free_entry_assignment (queue_entry_index, p_cpu_queue^.queue_header.
                queue_entry_assignment_table);
        IFEND;
      IFEND;

    FOREND /search_for_incomplete_actions/;

    STRINGREP (message, message_length, 'Server ', mainframe_name, ' terminated', terminated_requests,
          ' of', queued_requests, ' queued requests');
    IF terminated_requests > 0 THEN
      display (message (1, message_length));
    IFEND;
    log_display ($pmt$ascii_logset[pmc$system_log], message (1, message_length));

    dfp$locate_server_translation (p_cpu_queue^.queue_header.destination_mainframe_id, mainframe_ordinal,
          mainframe_found);
    request_block.request := dfc$fsr_set_task_segment_state;
    request_block.inhibit_access_work := $dft$mainframe_set [mainframe_ordinal];
    request_block.terminate_access_work := $dft$mainframe_set [];
    i#call_monitor (#LOC (request_block), #SIZE (request_block));


  PROCEND dfp$timeout_requests_to_server;

?? EJECT ??

{
{   The procedure attempts to determines if it ok to send the request over
{ the server again.  If the request is restartable it is always ok, otherwise
{ it is only ok if we are SURE the server has not received the request.
{ The driver is assumed to be idled when this is called.

  PROCEDURE determine_queued_request_action
    (    remote_processor: dft$procedure_address_ordinal;
         rpc_buffer_header: dft$rpc_buffer_header;
         p_cpu_queue_entry: ^dft$cpu_queue_entry;
         p_driver_queue_entry: ^dft$driver_queue_entry;
         mainframe_name: pmt$mainframe_id;
         p_cpu_queue: ^dft$cpu_queue;
     VAR status: ost$status);

    VAR
      current_rpc_entry: dft$rpc_procedure_address_entry,
      display_string: string (80),
      length: integer;

    IF remote_processor <= dfc$last_system_procedure THEN
      current_rpc_entry := dfv$procedure_address_list [remote_processor];
    ELSE
      current_rpc_entry := p_cpu_queue^.queue_header.p_application_rpc_list^ [$integer (remote_processor) -
            $integer (dfc$last_system_procedure)];
    IFEND;
    IF current_rpc_entry.request_restartable = dfc$request_restartable THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$server_not_active, mainframe_name, status);
    ELSE { Determine transaction state}
      IF (p_cpu_queue_entry^.transaction_state IN $dft$transaction_state_set
            [dfc$null_state, dfc$queue_entry_available, dfc$queue_entry_assigned]) OR
            ((p_cpu_queue_entry^.transaction_state = dfc$request_queued) AND
            p_driver_queue_entry^.flags.driver_action) THEN

{ We are sure the request has not been sent yet.

        osp$set_status_abnormal (dfc$file_server_id, dfe$server_not_active, mainframe_name, status);
      ELSEIF p_cpu_queue_entry^.transaction_state IN $dft$transaction_state_set [dfc$response_received] THEN

{ The task will get around to it soon enough.

        status.normal := TRUE;
      ELSE { The server may have received the request.
        osp$set_status_abnormal (dfc$file_server_id, dfe$server_request_terminated,
              current_rpc_entry.debug_display, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, mainframe_name, status);
        STRINGREP (display_string, length, ' Job ', rpc_buffer_header.system_supplied_job_name,
              ' terminated ', current_rpc_entry.debug_display);
        IF dfv$file_server_debug_enabled THEN
          display (display_string (1, length));
        IFEND;
        log_display ($pmt$ascii_logset[pmc$system_log], display_string (1, length));
      IFEND;
    IFEND;
  PROCEND determine_queued_request_action;
MODEND dfm$timeout_requests_to_server;
