?? RIGHT := 110 ??
?? TITLE := ' NOS/VE File Server : Transfer MM I/O Data ', EJECT ??
MODULE dfm$transfer_mmio_data;

{ PURPOSE:
{    The purpose of this module is to provide the procedures invloved with
{    the transfer of Memory Manager IO data from the server mainframe to the
{    client mainframe.
{
{ NOTES:
{    1.The client procedure - DFP$GET_MMIO_DATA - is called by the command
{      GENERATE_PTU_SUMMARY. The server (remote) procedure is DFP$SEND_MMIO_DATA.
{
{    2.Data is collected on the server side only if the executing modules of
{      IOM$PROCESS_IO_COMPLETIONS and MMM$FILE_SERVER_PROCESSOR had been
{      compiled with the statement DFV$PERF_TESTS=TRUE in the specified
{      selection_criteria file.


?? NEWTITLE := ' Global Declarations ', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc amt$fetch_attributes
*copyc amp$put_next
*copyc amp$return
*copyc amv$nil_file_identifier
*copyc clp$get_value
*copyc clp$scan_command_line
*copyc clp$scan_parameter_list
*copyc dfd$driver_queue_types
*copyc dfd$request_package
*copyc dfe$error_condition_codes
*copyc dfi$display
*copyc dfi$fsp_open_close
*copyc dfp$crack_mainframe_id
*copyc dfp$find_mainframe_id
*copyc dfp$send_remote_procedure_call
*copyc dft$procedure_address_ordinal
*copyc dft$rpc_buffer_header
*copyc dft$rpc_parameters
*copyc dfv$trace_count
*copyc i#current_sequence_position
*copyc mmp$free_pages
*copyc osp$append_status_parameter
*copyc osp$disestablish_cond_handler
*copyc osp$establish_block_exit_hndlr
*copyc osp$set_status_abnormal
*copyc osp$set_status_from_condition
*copyc pfp$attach
*copyc pfp$begin_system_authority
*copyc pfp$end_system_authority
*copyc pmp$get_mainframe_id
*copyc pmp$zero_out_table
?? POP ??

{   Format of request sent from client

  TYPE
    dft$rpc_mmio_request_header = record
      client_mainframe: pmt$mainframe_id,
      free_pages: boolean,
      family: ost$name,
      user: ost$name,
      file: ost$name
    recend;

{   Format of data returned from server

  TYPE
    dft$rpc_mmio_data_header = record
      trace_count: integer,
      number_of_io_requests: integer,
      total_io_request_time: integer,
      max_io_request_time: integer,
      number_of_allocate_requests: integer,
      total_allocate_request_time: integer,
      max_allocate_request_time: integer,
    recend;

?? TITLE := '  NOS/VE File Server : Client: [XDCL, #GATE] dfp$get_mmio_data ', EJECT ??

  PROCEDURE [XDCL, #GATE] dfp$get_mmio_data
    (    parameter_list: clt$parameter_list;
     VAR status: ost$status);

{ pdt get_mmio_data_pdt       (
{ family, f: name = testing
{ mmio_file, mf: file = mmio_file
{ free_pages: boolean = TRUE
{ user: name
{ file: name
{ status)

?? PUSH (LISTEXT := ON) ??

    VAR
      get_mmio_data_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table :=
            [^get_mmio_data_pdt_names, ^get_mmio_data_pdt_params];

    VAR
      get_mmio_data_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 8] of
            clt$parameter_name_descriptor := [['FAMILY', 1], ['F', 1], ['MMIO_FILE', 2], ['MF', 2],
            ['FREE_PAGES', 3], ['USER', 4], ['FILE', 5], ['STATUS', 6]];

    VAR
      get_mmio_data_pdt_params: [STATIC, READ, cls$pdt_parameters] array [1 .. 6] of
            clt$parameter_descriptor := [

{ FAMILY F }
      [[clc$optional_with_default, ^get_mmio_data_pdt_dv1], 1, 1, 1, 1, clc$value_range_not_allowed,
            [NIL, clc$name_value, 1, osc$max_name_size]],

{ MMIO_FILE MF }
      [[clc$optional_with_default, ^get_mmio_data_pdt_dv2], 1, 1, 1, 1, clc$value_range_not_allowed,
            [NIL, clc$file_value]],

{ FREE_PAGES }
      [[clc$optional_with_default, ^get_mmio_data_pdt_dv3], 1, 1, 1, 1, clc$value_range_not_allowed,
            [NIL, clc$boolean_value]],

{ USER }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ FILE }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ STATUS }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed,
            [NIL, clc$variable_reference, clc$array_not_allowed, clc$status_value]]];

    VAR
      get_mmio_data_pdt_dv1: [STATIC, READ, cls$pdt_names_and_defaults] string (7) := 'testing';

    VAR
      get_mmio_data_pdt_dv2: [STATIC, READ, cls$pdt_names_and_defaults] string (9) := 'mmio_file';

    VAR
      get_mmio_data_pdt_dv3: [STATIC, READ, cls$pdt_names_and_defaults] string (4) := 'TRUE';

?? POP ??
?? NEWTITLE := 'clean_up', EJECT ??

    PROCEDURE clean_up;

      VAR
        ignore_status: ost$status;

      IF mmio_file_id <> amv$nil_file_identifier THEN
        dfp$fsp_close (mmio_file_id, seqp, ignore_status);
      IFEND;

    PROCEND clean_up;
?? OLDTITLE, EJECT ??

    CONST
      real_mics_to_seconds = 1.0e6;

?? NEWTITLE := 'dfp$remote_procedure_call_ch', EJECT ??

{ PURPOSE:
{   This procedure is a condition handler established to call a routine to clear the assignment of a task
{   services queue_entry if a task aborts with a queue_entry assigned to it.  The queue_entry must be clear
{   before the task can safely exit.

    PROCEDURE dfp$remote_procedure_call_ch
      (    condition: pmt$condition;
           cond_desc: ^pmt$condition_information;
           save: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      dfp$ch_cleanup;
      IF use_abort_handler THEN
        clean_up;
      IFEND;
      osp$set_status_from_condition (dfc$file_server_id, condition, save, status, handler_status);
      EXIT dfp$get_mmio_data;

    PROCEND dfp$remote_procedure_call_ch;
*block
*copyc dfp$begin_ch_remote_proc_call
*copyc dfp$end_ch_remote_proc_call
*blockend
?? OLDTITLE, EJECT ??
    VAR
      allowed_when_server_deactivated: boolean,
      family: ost$name,
      file: ost$name,
      free_pages: boolean,
      ignore_byte_address: amt$file_byte_address,
      ignore_eoi: amt$file_byte_address,
      line: string (200),
      line_size: integer,
      local_status: ost$status,
      mmio_file_id: amt$file_identifier,
      mmio_file_name: amt$local_file_name,
      p_receive_buffer: dft$p_receive_parameters,
      p_receive_data: dft$p_receive_data,
      p_send_buffer: dft$p_send_parameters,
      p_send_data: dft$p_send_data,
      p_mmio_data_header: ^dft$rpc_mmio_data_header,
      p_mmio_request_header: ^dft$rpc_mmio_request_header,
      procedure_ordinal: dft$procedure_address_ordinal,
      queue_entry_location: dft$rpc_queue_entry_location,
      real_ave: real,
      real_max: real,
      receive_buffer_size: dft$send_parameter_size,
      receive_data_size: dft$send_data_size,
      request_restartable: boolean,
      send_buffer_size: dft$send_parameter_size,
      send_data_size: dft$send_data_size,
      seqp: ^SEQ ( * ),
      server_location: dft$server_location,
      start_time: integer,
      use_abort_handler: boolean,
      user: ost$name,
      value: clt$value;

    status.normal := TRUE;
    local_status.normal := TRUE;

    { Crack parameters.
    clp$scan_parameter_list (parameter_list, get_mmio_data_pdt, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    clp$get_value ('FAMILY', 1, 1, clc$low, value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    server_location.server_location_selector := dfc$family_name;
    server_location.family_name := value.name.value;
    family := value.name.value;

    clp$get_value ('MMIO_FILE', 1, 1, clc$low, value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    mmio_file_name := value.file.local_file_name;

    clp$get_value ('FREE_PAGES', 1, 1, clc$low, value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    free_pages := value.bool.value;

    clp$get_value ('USER', 1, 1, clc$low, value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    IF value.kind <> clc$unknown_value THEN
      user := value.name.value;
    ELSE
      user := '';
    IFEND;

    clp$get_value ('FILE', 1, 1, clc$low, value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    IF value.kind <> clc$unknown_value THEN
      file := value.name.value;
    ELSE
      file := '';
    IFEND;

    use_abort_handler := FALSE;
    #SPOIL (use_abort_handler);
    request_restartable := TRUE;
    allowed_when_server_deactivated := FALSE;

    dfp$begin_ch_remote_proc_call (server_location, allowed_when_server_deactivated, queue_entry_location,
          p_send_buffer, p_send_data, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pmp$zero_out_table (p_send_buffer, #SIZE (p_send_buffer^));
    NEXT p_mmio_request_header IN p_send_buffer;
    pmp$get_mainframe_id (p_mmio_request_header^.client_mainframe, status);
    IF NOT status.normal THEN
      dfp$end_ch_remote_proc_call (queue_entry_location, local_status);
      RETURN;
    IFEND;

    p_mmio_request_header^.free_pages := free_pages;
    p_mmio_request_header^.family := family;
    p_mmio_request_header^.user := user;
    p_mmio_request_header^.file := file;

    procedure_ordinal := dfc$send_mmio_data;
    send_buffer_size := #SIZE (dft$rpc_mmio_request_header);
    send_data_size := 0;

    dfp$send_remote_procedure_call (queue_entry_location, procedure_ordinal, send_buffer_size, send_data_size,
          p_receive_buffer, p_receive_data, status);
    IF NOT status.normal THEN
      display (' ABNORMAL STATUS FROM dfp$get_mmio_data ');
      dfp$end_ch_remote_proc_call (queue_entry_location, local_status);
      RETURN;
    IFEND;

    { Process receive buffer
    NEXT p_mmio_data_header IN p_receive_buffer;
    mmio_file_id := amv$nil_file_identifier;

  /process_mmio/
    BEGIN
      dfp$fsp_open (mmio_file_name, amc$record, {read_not_write} FALSE,
           {open_for_attach} FALSE, {seq_and_free_behind} FALSE, 'dfp$get_mmio_data',
           mmio_file_id, seqp, ignore_eoi, status);
      IF NOT status.normal THEN
        EXIT /process_mmio/;
      IFEND;
      use_abort_handler := TRUE;
      #SPOIL (use_abort_handler);

      IF p_mmio_data_header^.number_of_io_requests > 0 THEN
        real_ave := $REAL (p_mmio_data_header^.total_io_request_time) /
              $REAL (p_mmio_data_header^.number_of_io_requests);
        real_ave := real_ave / real_mics_to_seconds;
      ELSE
        real_ave := $REAL (0);
      IFEND;

      real_max := $REAL (p_mmio_data_header^.max_io_request_time) / real_mics_to_seconds;
      STRINGREP (line, line_size, ' ptu@mon_ave_io_time=''', real_ave: 9: 5, ''';ptu@mon_io_count=''',
            p_mmio_data_header^.number_of_io_requests, ''';ptu@mon_max_io_time=''', real_max: 9: 5, '''');
      amp$put_next (mmio_file_id, ^line, line_size, ignore_byte_address, status);
      IF NOT status.normal THEN
        EXIT /process_mmio/;
      IFEND;

      IF p_mmio_data_header^.number_of_allocate_requests > 0 THEN
        real_ave := $REAL (p_mmio_data_header^.total_allocate_request_time) /
              $REAL (p_mmio_data_header^.number_of_allocate_requests);
        real_ave := real_ave / real_mics_to_seconds;
      ELSE
        real_ave := $REAL (0);
      IFEND;

      real_max := $REAL (p_mmio_data_header^.max_allocate_request_time) / real_mics_to_seconds;
      STRINGREP (line, line_size, ' ptu@mon_ave_allocate_time=''', real_ave: 9: 5,
            ''';ptu@mon_allocate_count=''', p_mmio_data_header^.number_of_allocate_requests,
            ''';ptu@mon_max_allocate_time=''', real_max: 9: 5, '''');
      amp$put_next (mmio_file_id, ^line, line_size, ignore_byte_address, status);
      IF NOT status.normal THEN
        EXIT /process_mmio/;
      IFEND;

      STRINGREP (line, line_size, ' ptu@mon_trace_count=', p_mmio_data_header^.trace_count);
      amp$put_next (mmio_file_id, ^line, line_size, ignore_byte_address, status);
    END /process_mmio/;

    IF mmio_file_id <> amv$nil_file_identifier THEN
      dfp$fsp_close (mmio_file_id, seqp, status);
      use_abort_handler := FALSE;
      #SPOIL (use_abort_handler);
    IFEND;

    dfp$end_ch_remote_proc_call (queue_entry_location, local_status);

    IF status.normal THEN
      status := local_status;
    IFEND;

  PROCEND dfp$get_mmio_data;

?? TITLE := ' NOS/VE File Server : Server : [XDCL] dfp$send_mmio_data ', EJECT ??

  PROCEDURE [XDCL] dfp$send_mmio_data
    (VAR p_param_received_from_client {Input} : dft$p_receive_parameters;
     VAR p_data_from_client {Input} : dft$p_receive_data;
     VAR p_send_to_client_params {^Output} : dft$p_send_parameters;
     VAR p_data_to_client {^Output} : dft$p_send_data;
     VAR send_parameters_length: dft$send_parameter_size;
     VAR data_size_to_send_to_client: dft$send_data_size;
     VAR status: ost$status);

?? NEWTITLE := 'abort_handler', EJECT ??

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

       clean_up;

    PROCEND abort_handler;
?? TITLE := 'clean_up', EJECT ??

    PROCEDURE clean_up;

      VAR
        ignore_status: ost$status;

      IF file_id <> amv$nil_file_identifier THEN
        dfp$fsp_close (file_id, seqp, ignore_status);
      IFEND;
      pfp$end_system_authority;
    PROCEND clean_up;
?? OLDTITLE, EJECT ??

    VAR
      client_mainframe: pmt$mainframe_id,
      cycle_selector: pft$cycle_selector,
      host_is_server_to_client: boolean,
      eoi: amt$file_byte_address,
      file_id: amt$file_identifier,
      file_position: amt$file_position,
      frep_line: string (250),
      frep_size: integer,
      local_status: ost$status,
      mainframe_found: boolean,
      password: pft$password,
      path: array [1 .. 3] of ost$name,
      p_cpu_queue: ^dft$cpu_queue,
      p_queue_interface_table: dft$p_queue_interface_table,
      p_q_interface_directory_entry: ^dft$q_interface_directory_entry,
      p_mmio_request_header: ^dft$rpc_mmio_request_header,
      p_send_mmio_data_header: ^dft$rpc_mmio_data_header,
      ptu_lfn: amt$local_file_name,
      queue_index: dft$queue_index,
      seqp: ^SEQ ( * ),
      share_selections: pft$share_selections,
      usage_selections: pft$usage_selections;

    status.normal := TRUE;

    pmp$zero_out_table (p_send_to_client_params, #SIZE (p_send_to_client_params^));
    pmp$zero_out_table (p_data_to_client, #SIZE (p_data_to_client^));
    NEXT p_mmio_request_header IN p_param_received_from_client;
    client_mainframe := p_mmio_request_header^.client_mainframe;
    host_is_server_to_client := TRUE;
    dfp$find_mainframe_id (client_mainframe, 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_client, client_mainframe, status);
      RETURN;
    IFEND;


    NEXT p_send_mmio_data_header IN p_send_to_client_params;

    p_send_mmio_data_header^.trace_count := dfv$trace_count;
    p_send_mmio_data_header^.number_of_io_requests := p_cpu_queue^.queue_header.monitor_io [dfc$monitor_io].
          number_of_requests;
    p_send_mmio_data_header^.total_io_request_time := p_cpu_queue^.queue_header.monitor_io [dfc$monitor_io].
          total_request_time;
    p_send_mmio_data_header^.max_io_request_time := p_cpu_queue^.queue_header.monitor_io [dfc$monitor_io].
          max_request_time;
    p_send_mmio_data_header^.number_of_allocate_requests := p_cpu_queue^.queue_header.
          monitor_io [dfc$monitor_allocate].number_of_requests;
    p_send_mmio_data_header^.total_allocate_request_time := p_cpu_queue^.queue_header.
          monitor_io [dfc$monitor_allocate].total_request_time;
    p_send_mmio_data_header^.max_allocate_request_time := p_cpu_queue^.queue_header.
          monitor_io [dfc$monitor_allocate].max_request_time;

    send_parameters_length := #SIZE (dft$rpc_mmio_data_header);
    data_size_to_send_to_client := 0;

    p_cpu_queue^.queue_header.monitor_io [dfc$monitor_io].total_request_time := 0;
    p_cpu_queue^.queue_header.monitor_io [dfc$monitor_io].number_of_requests := 0;
    p_cpu_queue^.queue_header.monitor_io [dfc$monitor_io].max_request_time := 0;
    p_cpu_queue^.queue_header.monitor_io [dfc$monitor_allocate].total_request_time := 0;
    p_cpu_queue^.queue_header.monitor_io [dfc$monitor_allocate].number_of_requests := 0;
    p_cpu_queue^.queue_header.monitor_io [dfc$monitor_allocate].max_request_time := 0;
    dfv$trace_count := 0;

    IF p_mmio_request_header^.free_pages THEN
      ptu_lfn := 'frep_lfn';
      path [1] := p_mmio_request_header^.family;
      path [2] := p_mmio_request_header^.user;
      path [3] := p_mmio_request_header^.file;
      cycle_selector.cycle_option := pfc$highest_cycle;
      password := '';
      usage_selections := $pft$usage_selections [pfc$read, pfc$shorten, pfc$modify];
      share_selections := $pft$share_selections [];
      osp$establish_block_exit_hndlr (^abort_handler);
      pfp$begin_system_authority;
      pfp$attach (ptu_lfn, path, cycle_selector, password, usage_selections, share_selections, pfc$no_wait,
            status);

      file_id := amv$nil_file_identifier;

      IF status.normal THEN
        {  Open for write to free pages.
        dfp$fsp_open (ptu_lfn,  amc$segment, {read_not_write} FALSE, {open_for_attach} FALSE,
              {seq_and_free_behind} FALSE, 'dfp$get_mmio_data', file_id, seqp, eoi, status);
        IF NOT status.normal THEN
          amp$return (ptu_lfn, local_status);
          RETURN;
        IFEND;

        RESET seqp;
        mmp$free_pages (seqp, eoi, osc$wait, status);

        IF NOT status.normal THEN
          amp$return (ptu_lfn, local_status);
          RETURN;
        IFEND;

        dfp$fsp_close (file_id, seqp, status);

        amp$return (ptu_lfn, local_status);
        IF status.normal THEN
          status := local_status;
        IFEND;
      IFEND;
      pfp$end_system_authority;
      osp$disestablish_cond_handler;
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    IFEND {free pages };

  PROCEND dfp$send_mmio_data;

MODEND dfm$transfer_mmio_data;

