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

{
{ PURPOSE:
{   To terminate the activities on a server mainframe which are associated
{   with a terminated or timed out client mainframe.
{
{ NOTES:
{   1. The driver queue header IDLE will be set and a wait executed to ensure
{      that all PP activity has ceased.
{   2. The convention established by dfm$clone_task_process of using
{      number_of_monitor_queue_entries + 1 as the queue entry index for
{      the monitor clone task is followed here.

?? NEWTITLE := '    Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc dfc$esm_driver_error_codes
*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$client_mainframe_file
*copyc dft$cpu_queue
*copyc dft$entry_type
*copyc dft$rb_file_server_request
*copyc dfv$file_server_debug_enabled
*copyc dfv$p_clone_tasks_status
*copyc dfv$null_global_task_id
*copyc mmt$server_state
*copyc osc$server_state_change
*copyc ost$caller_identifier
*copyc pmt$task_status
*copyc pmp$wait
?? POP ??
*copyc dfp$find_mainframe_id
*copyc i#call_monitor
*copyc osp$set_status_abnormal
*copyc pmp$cause_condition_in_tasks
*copyc pmp$wait
*copyc pmp$ready_task
?? TITLE := '    [XDCL] dfp$term_processing_on_server', EJECT ??

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

    VAR
      host_is_server_to_client: boolean,
      mainframe_found: boolean,
      number_of_monitor_queue_entries: 0 .. dfc$max_queue_entries,
      number_of_task_queue_entries: dft$queue_entry_index,
      p_cpu_queue: ^dft$cpu_queue,
      p_cpu_queue_entry: ^dft$cpu_queue_entry,
      p_driver_queue: ^dft$driver_queue,
      p_queue_interface_table: dft$p_queue_interface_table,
      p_q_interface_directory_entry: ^dft$q_interface_directory_entry,
      q_d_index: dft$queue_directory_index,
      queue_entry_index: dft$queue_entry_index,
      queue_index: dft$queue_index,
      request_block: dft$rb_file_server_request,
      response_buffer_entry: dft$fs_pp_response,
      task_still_active: boolean,
      total_queue_entries: dft$queue_entry_index;

    status.normal := TRUE;
    host_is_server_to_client := TRUE;
    dfp$find_mainframe_id (mainframe_name, host_is_server_to_client, 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;
    IF p_cpu_queue^.queue_header.p_remote_application_info <> NIL THEN
      { The application may be processing a remote procedure call
      log_display ($pmt$ascii_logset [pmc$job_log, pmc$system_log],
            ' Calling pmp$cause_condition_in_tasks for osc$server_state_change');
      pmp$cause_condition_in_tasks (osc$server_state_change);
    IFEND;

    number_of_monitor_queue_entries := p_cpu_queue^.queue_header.number_of_monitor_queue_entries;
    number_of_task_queue_entries := p_cpu_queue^.queue_header.number_of_task_queue_entries;
    p_driver_queue := p_queue_interface_table^.queue_directory.driver_queue_pva_directory [queue_index].
          p_driver_queue;
    total_queue_entries := p_driver_queue^.queue_header.number_of_queue_entries;

{ Idle PP driver

    p_driver_queue^.queue_header.flags.idle := TRUE;
    pmp$wait (2000, 2000);

{Terminate task clone tasks

    IF dfv$p_clone_tasks_status <> NIL THEN

    /check_task_queue_entries/
      FOR queue_entry_index := dfc$poll_queue_index + number_of_monitor_queue_entries +
            1 TO total_queue_entries DO
        p_cpu_queue_entry := ^p_cpu_queue^.queue_entries [queue_entry_index];
        IF (p_cpu_queue_entry^.global_task_id <> dfv$null_global_task_id) AND
              (NOT dfv$p_clone_tasks_status^ [queue_entry_index].complete) THEN
          p_driver_queue^.queue_entries [queue_entry_index].flags.subsystem_action := TRUE;
          pmp$ready_task (p_cpu_queue_entry^.global_task_id, status);
        IFEND;
        IF NOT status.normal THEN
          IF dfv$file_server_debug_enabled THEN
            display (' DFM$TERM_PROCESSING_ON_SERVER received abnormal status ' CAT 'from PMP$READY_TASK.');
            display_status (status);
          IFEND;
          status.normal := TRUE;
        IFEND;
      FOREND /check_task_queue_entries/;
    IFEND;

{ Terminate monitor task

    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 := TRUE;
    response_buffer_entry.response_parameter.error_condition := dfc$destination_machine_down;
    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;

  /check_monitor_queue_entries/
    FOR queue_entry_index := 1 TO total_queue_entries DO
      p_cpu_queue_entry := ^p_cpu_queue^.queue_entries [queue_entry_index];
      IF p_cpu_queue_entry^.processor_type <> dfc$monitor THEN
        CYCLE /check_monitor_queue_entries/;
      IFEND;

    /wait_till_io_complete/
      REPEAT
        pmp$wait (10, 10);
        #SPOIL (p_cpu_queue_entry^.p_server_iocb^.server_state);
        #SPOIL (p_cpu_queue_entry^.data_pages_locked);
      UNTIL (p_cpu_queue_entry^.p_server_iocb^.server_state = mmc$ss_waiting) OR
            p_cpu_queue_entry^.data_pages_locked;

      IF p_cpu_queue_entry^.data_pages_locked THEN
        response_buffer_entry.queue_entry_index := queue_entry_index;
        request_block.one_word_response := response_buffer_entry;
        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));
      IFEND;

    /wait_till_not_waiting/
      WHILE (p_cpu_queue_entry^.p_server_iocb^.server_state <> mmc$ss_waiting) DO
        #SPOIL (p_cpu_queue_entry^.p_server_iocb^.server_state);
        pmp$wait (10, 10);
      WHILEND /wait_till_io_complete/;

    FOREND /check_monitor_queue_entries/;

{Wait until all tasks complete

    IF dfv$p_clone_tasks_status <> NIL THEN

    /wait_tasks_completion/
      REPEAT
        task_still_active := FALSE;

      /check_each_clone_task/
        FOR queue_entry_index := LOWERBOUND (dfv$p_clone_tasks_status^)
              TO UPPERBOUND (dfv$p_clone_tasks_status^) DO
          task_still_active := NOT dfv$p_clone_tasks_status^ [queue_entry_index].complete;
          IF task_still_active THEN
            IF p_cpu_queue^.queue_entries [queue_entry_index].global_task_id = dfv$null_global_task_id THEN
              task_still_active := FALSE;
            ELSE
              p_driver_queue^.queue_entries [queue_entry_index].flags.subsystem_action := TRUE;
              pmp$ready_task (p_cpu_queue^.queue_entries [queue_entry_index].global_task_id, status);
            IFEND;
            IF task_still_active THEN

{ Message to outside ?????

              pmp$wait (1000, 1000);
              EXIT /check_each_clone_task/;
            IFEND;
          IFEND;
          p_driver_queue^.queue_entries [queue_entry_index].flags.subsystem_action := FALSE;
          p_driver_queue^.queue_entries [queue_entry_index].error_condition := 0;
        FOREND /check_each_clone_task/;
      UNTIL NOT task_still_active; {/wait_tasks_completion/}

    IFEND;
    p_driver_queue^.queue_entries [dfc$poll_queue_index + 1].flags.subsystem_action := FALSE;

  PROCEND dfp$term_processing_on_server;
MODEND dfm$term_processing_on_server
