MODULE osm$spi_support;

?? PUSH (LISTEXT := ON) ??
*copyc osd$default_pragmats
*copyc amt$local_file_name
*copyc jmv$jcb
*copyc ofp$display_status_message
*copyc osp$establish_condition_handler
*copyc osp$disestablish_cond_handler
*copyc osp$fetch_spi_lock
*copyc osp$release_spi_r1_support
*copyc osp$reserve_spi_r1_support
*copyc osp$set_status_abnormal
*copyc osp$set_status_from_condition
*copyc osp$start_spi_collection_r1
*copyc osp$stop_spi_collection_r1
*copyc oss$task_private
*copyc ost$caller_identifier
*copyc ost$keypoint_control
*copyc ost$execution_control_block
*copyc ost$processor_id_set
*copyc ost$spi_types
*copyc ost$wait
*copyc osv$page_size
*copyc osv$spi_control
*copyc osv$task_private_heap
*copyc pmp$continue_to_cause
*copyc pmp$disestab_end_hndlr_in_ring
*copyc pmp$establish_end_hndlr_in_ring
*copyc pmp$execute_with_less_privilege
*copyc pmp$get_compact_date_time
*copyc pmp$get_cpu_attributes
*copyc pmp$log
*copyc pmp$log_ascii
*copyc pmp$long_term_wait
*copyc pmp$terminate

?? POP ??

  VAR
    osv$spi_task_data_p: [oss$task_private] ^ost$spi_task_data;

  TYPE
    ost$spi_task_data = record
      task_id: pmt$task_id,
      task_status: pmt$task_status,
    recend;


?? TITLE := 'PROCEDURE [XDCL, #GATE] osp$reserve_spi_environment', EJECT ??

  PROCEDURE [XDCL, #GATE] osp$reserve_spi_environment
    (    spi_identifier: ost$spi_identifier;
         collection_file: amt$local_file_name;
         number_of_spi_samples: ost$number_of_spi_samples;
         spi_sampling_interval: ost$spi_sampling_interval;
         wait: ost$wait;
         processor_id_set: ost$processor_id_set;
         data_string: string (32);
     VAR status: ost$status);

*copyc osh$reserve_spi_environment

    PROCEDURE handler
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           stack_frame_save: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      handler_status.normal := TRUE;
      IF condition.selector = ifc$interactive_condition THEN
        IF condition.interactive_condition = ifc$terminate_break THEN
          osp$set_status_from_condition ('OS', condition, stack_frame_save,
                status, handler_status);
          EXIT osp$reserve_spi_environment;
        IFEND;
      ELSE
        pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
      IFEND;
      handler_status.normal := TRUE;
    PROCEND handler;

?? EJECT ??

    VAR
      available_processor_set: ost$processor_id_set,
      caller_id: ost$caller_identifier,
      cpu_attributes: pmt$cpu_attributes,
      lstatus: ost$status,
      new_processor_id_set: ost$processor_id_set,
      parameter: cell,
      parameter_list: ^pmt$program_parameters,
      processor: ost$processor_id,
      program_attributes: ^pmt$program_attributes,
      program_description: ^pmt$program_description;

    status.normal := TRUE;
    #CALLER_ID (caller_id);
    osp$establish_condition_handler (^handler, FALSE);

{  A check is made on the state of the CPU's configured on the system.
{  A set is constructed to contain only those CPU's that are configured
{  and ON.  A new processor_id_set is then constructed to be the intersection
{  of the CPU's chosen by the user and the CPU's that are configured and ON.
{  This will prevent SPI from trying to sample a CPU that is not active.

   pmp$get_cpu_attributes(cpu_attributes, status);
   IF NOT status.normal THEN
     RETURN;
   IFEND;

   FOR processor:= 0 TO cpu_attributes.highest_defined_cpu_number DO
     IF cpu_attributes.cpu[processor].state = pmc$processor_state_on THEN
       available_processor_set := available_processor_set + $ost$processor_id_set[processor];
     IFEND;
   FOREND;

   new_processor_id_set := processor_id_set * available_processor_set;

    REPEAT
      osp$reserve_spi_r1_support (spi_identifier, collection_file,
            number_of_spi_samples, spi_sampling_interval, new_processor_id_set,
            data_string, status);

      IF NOT status.normal THEN
        IF status.condition = ose$spi_environment_not_avail THEN
          IF wait = osc$wait THEN
            ofp$display_status_message ('waiting for SPI environment',
                  lstatus);
            pmp$long_term_wait (30000, 30000);
          ELSE
            RETURN;
          IFEND;
        ELSEIF status.condition = ose$job_has_spi_environment THEN
          RETURN;
        ELSE
          RETURN;
        IFEND;
      IFEND;
    UNTIL status.normal;

    ALLOCATE osv$spi_task_data_p IN osv$task_private_heap^;
    PUSH program_description: [[REP #SIZE (pmt$program_attributes) OF cell]];
    RESET program_description;
    NEXT program_attributes IN program_description;
    program_attributes^.contents := $pmt$prog_description_contents
          [pmc$starting_proc_specified];
    program_attributes^.starting_procedure := 'OSP$SPI_DATA_COLLECTOR';
    parameter_list := #SEQ (parameter);
    ofp$display_status_message ('Waiting for spi collector to start.', status);
    pmp$execute_with_less_privilege (caller_id.ring, program_description^, parameter_list^,
          osc$nowait, FALSE, osv$spi_task_data_p^.task_id, osv$spi_task_data_p^.task_status,
          status);
    IF status.normal AND osv$spi_task_data_p^.task_status.complete THEN
      IF NOT osv$spi_task_data_p^.task_status.status.normal THEN
{
{ CAUTION !!! The copy of status must occur before the call to
{ osp$release_spi_environment which frees osv$spi_stask_data_p.
{
        status := osv$spi_task_data_p^.task_status.status;
        osp$release_spi_environment (lstatus);
        osp$disestablish_cond_handler;
        RETURN;
      IFEND;
    IFEND;

    REPEAT
      pmp$long_term_wait (100000000, 100000000);
    UNTIL osv$spi_control.pp_available OR
       osv$spi_task_data_p^.task_status.complete;
    IF osv$spi_task_data_p^.task_status.complete THEN
      IF NOT osv$spi_task_data_p^.task_status.status.normal THEN
{
{ CAUTION !!! The copy of status must occur before the call to
{ osp$release_spi_environment which frees osv$spi_stask_data_p.
{
        status := osv$spi_task_data_p^.task_status.status;
        osp$release_spi_environment (lstatus);
        osp$disestablish_cond_handler;
        RETURN;
      IFEND;
    IFEND;
    osp$disestablish_cond_handler;

    pmp$establish_end_hndlr_in_ring (^end_handler, caller_id.ring, lstatus);

  PROCEND osp$reserve_spi_environment;
?? TITLE := 'PROCEDURE end_handler', EJECT ??

  PROCEDURE end_handler
    (    termination_status: ost$status;
     VAR status: ost$status);

    status.normal := TRUE;
    pmp$log_ascii ('SPI COLLECTION ABORTED', $pmt$ascii_logset
          [pmc$system_log, pmc$job_log], pmc$msg_origin_system, status);

    osp$release_spi_environment (status);

  PROCEND end_handler;


?? TITLE := 'PROCEDURE [XDCL, #GATE] osp$release_spi_environment', EJECT ??

  PROCEDURE [XDCL, #GATE] osp$release_spi_environment
    (VAR status: ost$status);

*copyc osh$release_spi_environment

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

      handler_status.normal := TRUE;
      IF handler_invoked THEN
        RETURN;
      IFEND;
      IF condition.selector = ifc$interactive_condition THEN
        IF condition.interactive_condition = ifc$terminate_break THEN
          pmp$continue_to_cause (pmc$execute_standard_procedure,
                handler_status);
          RETURN;
        IFEND;
      IFEND;
      handler_invoked := TRUE;
      pmp$disestab_end_hndlr_in_ring (^end_handler, caller_id.ring, status);
      osp$set_status_from_condition ('OS', condition, save_area, status,
            handler_status);
      IF NOT status.normal THEN
        handler_status := status;
      IFEND;
      EXIT osp$release_spi_environment;
    PROCEND handler;

?? EJECT ??

    VAR
      caller_id: ost$caller_identifier,
      i: integer,
      handler_invoked: boolean,
      lstatus: ost$status,
      OFF: integer;

    #CALLER_ID (caller_id);
    status.normal := TRUE;
    lstatus.normal := TRUE;
    osp$fetch_spi_lock (i);
    IF (i = 0) OR (osv$spi_control.jsn <> jmv$jcb.system_name) THEN
      osp$set_status_abnormal ('OS', ose$spi_illegal_request, '', status);
      RETURN;
    IFEND;

    handler_invoked := FALSE;
    osp$establish_condition_handler (^handler, TRUE);

    IF ((osv$spi_control.operation_status = osc$spi_wait_for_start) OR
          (osv$spi_control.operation_status = osc$spi_start_collecting)) THEN
      osp$stop_spi_collection_r1 (status);
    IFEND;
    osp$release_spi_r1_support (status);
    IF status.normal THEN
      pmp$long_term_wait (40000, 40000);
    IFEND;
    IF NOT osv$spi_task_data_p^.task_status.complete THEN
      pmp$terminate (osv$spi_task_data_p^.task_id, status);
    IFEND;
    pmp$disestab_end_hndlr_in_ring (^end_handler, caller_id.ring, lstatus);
    osp$disestablish_cond_handler;
    FREE osv$spi_task_data_p IN osv$task_private_heap^;
  PROCEND osp$release_spi_environment;

?? TITLE := 'PROCEDURE [XDCL, #GATE] osp$start_spi_collection', EJECT ??

  PROCEDURE [XDCL, #GATE] osp$start_spi_collection
    (VAR status: ost$status);

*copyc osh$start_spi_collection

    VAR
      i: integer;

    status.normal := TRUE;
    osp$fetch_spi_lock (i);
    IF (i = 0) OR (osv$spi_control.jsn <> jmv$jcb.system_name) THEN
      osp$set_status_abnormal ('OS', ose$spi_illegal_request, '', status);
      RETURN;
    IFEND;
    osp$start_spi_collection_r1 (status);

  PROCEND osp$start_spi_collection;

?? TITLE := 'PROCEDURE [XDCL, #GATE] osp$stop_spi_collection', EJECT ??

  PROCEDURE [XDCL, #GATE] osp$stop_spi_collection
    (VAR status: ost$status);

*copyc osh$stop_spi_collection

    VAR
      i: integer;

    status.normal := TRUE;
    osp$fetch_spi_lock (i);
    IF (i = 0) OR (osv$spi_control.jsn <> jmv$jcb.system_name) THEN
      osp$set_status_abnormal ('OS', ose$spi_illegal_request, '', status);
      RETURN;
    IFEND;
    osp$stop_spi_collection_r1 (status);

  PROCEND osp$stop_spi_collection;

MODEND osm$spi_support;
