?? RIGHT := 110 ??
?? NEWTITLE := 'OSM$I_AWAIT_ACTIVITY' ??
MODULE osm$i_await_activity;

{   PURPOSE:
{     The purpose of this request is to support the osp$i_await_activity_completion
{     request.

{   DESIGN:
{     The procedure contained in this module has an execution bracket
{     of 1, 3 and a call bracket of 13.

?? EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc ame$improper_file_id
*copyc nac$null_connection_id
*copyc nae$sk_socket_layer
*copyc osd$virtual_address
*copyc ose$await_activity_exceptions
*copyc oss$job_paged_literal
*copyc ost$caller_identifier
*copyc ost$hardware_subranges
*copyc ost$i_wait
*copyc ost$status
*copyc pmd$local_queues
*copyc pme$local_queue_exceptions
*copyc pmt$task_id
?? POP ??
*copyc baf$task_file_entry_p
*copyc iip$vt_check_data_available
*copyc iip$xt_check_upline
*copyc iip$xt_is_xterm_file
*copyc nap$check_connection
*copyc nap$check_data_available
*copyc nap$check_server_response
*copyc nap$check_switch_accept
*copyc nap$check_switch_offer
*copyc nap$check_title_translation
*copyc nap$remove_network_waits
*copyc nlp$sk_await_socket_offer
*copyc nlp$sk_lock_job_socket
*copyc nlp$sk_tcp_await_clear_to_send
*copyc nlp$sk_tcp_await_data_available
*copyc nlp$sk_tcp_check_accept_socket
*copyc nlp$sk_unlock_job_socket
*copyc nlp$udp_await_clear_to_send
*copyc nlp$udp_await_data_available
*copyc osp$append_status_integer
*copyc osp$establish_condition_handler
*copyc osp$disestablish_cond_handler
*copyc osp$pop_inhibit_job_recovery
*copyc osp$push_inhibit_job_recovery
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc pmp$await_nonempty_queue
*copyc pmp$continue_to_cause
*copyc pmp$long_term_wait
*copyc pmp$remove_await_nonempty_queue
*copyc pmp$verify_current_child
*copyc rfp$check_for_event
*copyc rfp$remove_waits
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] osp$i_await_activiy', EJECT ??

  PROCEDURE [XDCL, #GATE] osp$i_await_activity
    (    wait_list: ost$i_wait_list;
     VAR ready_index: integer;
     VAR complete: boolean;
     VAR status: ost$status);

    TYPE
      activity_index = 0 .. osc$maximum_offset;

    CONST
      local_clock = 0;

    VAR
      active_rhfam_wait: boolean,
      activity: activity_index,
      await_complete: boolean,
      await_status: ost$status,
      current_time: ost$free_running_clock,
      elapsed_time: ost$free_running_clock,
      exit_on_ready_task: boolean,
      exit_save_activity_index: activity_index,
      file_instance: ^bat$task_file_entry,
      ignore_status: ost$status,
      inhibit_job_recovery_pushed: boolean,
      job_socket: ^nat$sk_job_socket,
      null_list: boolean,
      requestor: ost$caller_identifier,
      start_time: ost$free_running_clock,
      task_has_gone_ready: boolean,
      wait_time: ost$free_running_clock;

?? NEWTITLE := '[INLINE] cleanup_active_waits', EJECT ??

    PROCEDURE [INLINE] cleanup_active_waits;

      IF NOT inhibit_job_recovery_pushed THEN {This check is for the conditin handler call
        osp$push_inhibit_job_recovery;
        inhibit_job_recovery_pushed := TRUE;
        #SPOIL (inhibit_job_recovery_pushed);
      IFEND;

      remove_await_nonempty_queue (1, UPPERBOUND (wait_list));
      nap$remove_network_waits (wait_list);

      IF active_rhfam_wait THEN
        rfp$remove_waits;
      IFEND;

      osp$pop_inhibit_job_recovery;
      inhibit_job_recovery_pushed := FALSE;
      #SPOIL (inhibit_job_recovery_pushed);

    PROCEND cleanup_active_waits;
?? OLDTITLE ??
?? NEWTITLE := 'dispose_of_condition', EJECT ??

    PROCEDURE dispose_of_condition
      (    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, jmc$job_resource_condition =
        pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
        EXIT osp$i_await_activity;
      = pmc$block_exit_processing =
        cleanup_active_waits;

        IF inhibit_job_recovery_pushed THEN
          osp$pop_inhibit_job_recovery;
          inhibit_job_recovery_pushed := FALSE;
          #SPOIL (inhibit_job_recovery_pushed);
        IFEND;
      ELSE
        pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
      CASEND;

    PROCEND dispose_of_condition;
?? OLDTITLE ??
?? NEWTITLE := 'remove_await_nonempty_queue', EJECT ??

    PROCEDURE [INLINE] remove_await_nonempty_queue
      (    starting_activity: activity_index;
           ending_activity: activity_index);

      VAR
        activity: activity_index;

      FOR activity := starting_activity TO ending_activity DO
        IF (wait_list [activity].activity = pmc$i_await_local_queue_message) THEN
          pmp$remove_await_nonempty_queue (wait_list [activity].qid);
        IFEND;
      FOREND;

    PROCEND remove_await_nonempty_queue;
?? OLDTITLE ??
?? EJECT ??

    #CALLER_ID (requestor);
    elapsed_time := 0;
    status.normal := TRUE;
    complete := FALSE;
    active_rhfam_wait := FALSE;
    await_status.normal := TRUE;
    wait_time := UPPERVALUE (ost$free_running_clock);
    task_has_gone_ready := FALSE;
    exit_on_ready_task := FALSE;

    inhibit_job_recovery_pushed := FALSE;
    #SPOIL (inhibit_job_recovery_pushed);

    osp$establish_condition_handler (^dispose_of_condition, {block_exit} TRUE);

    null_list := TRUE;
    REPEAT
      await_complete := FALSE;
      activity := 1;
      WHILE NOT await_complete AND (activity <= UPPERBOUND (wait_list)) AND await_status.normal DO
        CASE wait_list [activity].activity OF
        = osc$i_null_activity =
          ;

        = osc$i_await_time =
          null_list := FALSE;
          IF (elapsed_time >= (wait_list [activity].milliseconds * 1000)) THEN
            await_complete := TRUE;
          ELSEIF ((wait_list [activity].milliseconds * 1000) < wait_time) THEN
            wait_time := wait_list [activity].milliseconds * 1000;
          IFEND;

        = pmc$i_await_task_termination =
          null_list := FALSE;
          pmp$verify_current_child (wait_list [activity].task_id, await_complete);
          await_complete := NOT await_complete;

        = pmc$i_await_local_queue_message =
          null_list := FALSE;
          pmp$await_nonempty_queue (wait_list [activity].qid, requestor.ring, await_complete, await_status);

        = nac$i_await_server_response =
          null_list := FALSE;
          nap$check_server_response (wait_list [activity].file^, await_complete, await_status);

        = nac$i_await_switch_accept =
          null_list := FALSE;
          nap$check_switch_accept (wait_list [activity].file^, await_complete, await_status);

        = nac$i_await_connection =
          null_list := FALSE;
          nap$check_connection (wait_list [activity].server, await_complete, await_status);

        = nac$i_await_switch_offer =
          null_list := FALSE;
          nap$check_switch_offer (wait_list [activity].source, await_complete, await_status);

        = nac$i_await_activity_status =
          null_list := FALSE;
          await_complete := wait_list [activity].activity_status^.complete;

        = nac$i_await_data_available =
          null_list := FALSE;

          file_instance := baf$task_file_entry_p (wait_list [activity].file_identifier);
          IF file_instance = NIL THEN
            osp$set_status_condition (ame$improper_file_id, await_status);
          ELSE
            IF file_instance^.device_class = rmc$network_device THEN
              IF iip$xt_is_xterm_file (file_instance^.system_file_label) THEN
                iip$xt_check_upline (wait_list [activity].file_identifier, await_complete, await_status);
              ELSE {This is a not an xterm file.
                nap$check_data_available (wait_list [activity].file_identifier, await_complete,
                       await_status);
              IFEND;
            ELSE {rmc$terminal_device
              iip$vt_check_data_available (wait_list [activity].file_identifier, await_complete,
                    await_status);
            IFEND;
          IFEND;

        = nac$i_await_title_translation =
          null_list := FALSE;
          nap$check_title_translation (wait_list [activity].translation_request, await_complete,
                await_status);

        = nac$i_sk_await_clear_to_send =
          null_list := FALSE;
          osp$push_inhibit_job_recovery;
          inhibit_job_recovery_pushed := TRUE;
          #SPOIL (inhibit_job_recovery_pushed);

          nlp$sk_lock_job_socket (wait_list [activity].socket_identifier, job_socket);
          IF job_socket <> NIL THEN
            IF job_socket^.status = nac$sk_socket_open THEN
              IF job_socket^.socket_type = nac$sk_udp_socket THEN
                nlp$udp_await_clear_to_send (job_socket^.global_socket_id, {wait} TRUE,
                  await_complete);
              ELSEIF job_socket^.socket_type = nac$sk_tcp_socket THEN
                IF (job_socket^.tcp_socket_type = nlc$tcp_connect_socket) OR
                        (job_socket^.tcp_socket_type = nlc$tcp_accept_socket) THEN
                    nlp$sk_tcp_await_clear_to_send (job_socket^.connection_id, {wait} TRUE,
                      await_complete);
                ELSE { Either connect or listen not done.  Should this give a reject instead???
                  await_complete := TRUE;
                IFEND;
              IFEND;
            ELSE { Socket closed
              await_complete := TRUE;
            IFEND;
          ELSE { Unknown Socket
            osp$set_status_abnormal (nac$status_id, nae$sk_unknown_socket, '', await_status);
            osp$append_status_integer (osc$status_parameter_delimiter, wait_list [activity].socket_identifier,
                  10, TRUE, await_status);
          IFEND;
          nlp$sk_unlock_job_socket (wait_list [activity].socket_identifier);
          osp$pop_inhibit_job_recovery;
          inhibit_job_recovery_pushed := FALSE;
          #SPOIL (inhibit_job_recovery_pushed);

        = nac$i_sk_await_data_available =
          null_list := FALSE;
          osp$push_inhibit_job_recovery;
          inhibit_job_recovery_pushed := TRUE;
          #SPOIL (inhibit_job_recovery_pushed);

          nlp$sk_lock_job_socket (wait_list [activity].socket_id, job_socket);
          IF job_socket <> NIL THEN
            IF job_socket^.status = nac$sk_socket_open THEN
              IF job_socket^.socket_type = nac$sk_udp_socket THEN
                nlp$udp_await_data_available (job_socket^.global_socket_id, {wait} TRUE,
                  await_complete);
              ELSEIF job_socket^.socket_type = nac$sk_tcp_socket THEN
                IF (job_socket^.tcp_socket_type = nlc$tcp_connect_socket) OR
                      (job_socket^.tcp_socket_type = nlc$tcp_accept_socket) THEN
                  nlp$sk_tcp_await_data_available (job_socket^.connection_id, {wait} TRUE,
                    await_complete);
                ELSEIF job_socket^.tcp_socket_type = nlc$tcp_listen_socket THEN
                  nlp$sk_tcp_check_accept_socket (job_socket^.application, job_socket^.port,
                        job_socket^.bound_address, {wait} TRUE, await_complete);
                ELSE  { job_socket^.tcp_socket_type = nlc$tcp_null_socket
                  await_complete := TRUE;
                IFEND;
              IFEND;
            ELSE { Socket closed
              await_complete := TRUE;
            IFEND;
          ELSE { Unknown Socket
            osp$set_status_abnormal (nac$status_id, nae$sk_unknown_socket, '', await_status);
            osp$append_status_integer (osc$status_parameter_delimiter, wait_list [activity].socket_id, 10,
                  TRUE, await_status);
          IFEND;
          nlp$sk_unlock_job_socket (wait_list [activity].socket_id);
          osp$pop_inhibit_job_recovery;
          inhibit_job_recovery_pushed := FALSE;
          #SPOIL (inhibit_job_recovery_pushed);

        = nac$i_sk_await_socket_offer =
          null_list := FALSE;
          osp$push_inhibit_job_recovery;
          inhibit_job_recovery_pushed := TRUE;
          #SPOIL (inhibit_job_recovery_pushed);

          nlp$sk_await_socket_offer (wait_list [activity].source_job, {wait} TRUE, await_complete);

          osp$pop_inhibit_job_recovery;
          inhibit_job_recovery_pushed := FALSE;
          #SPOIL (inhibit_job_recovery_pushed);

        = rfc$i_await_server_response, rfc$i_await_incoming_connect, rfc$i_await_switch_offer,
              rfc$i_await_switch_accept, rfc$i_await_connection_event =
          null_list := FALSE;
          rfp$check_for_event (wait_list [activity], await_complete, await_status);
          IF await_status.normal THEN
            IF NOT await_complete THEN
              active_rhfam_wait := TRUE;
            IFEND;
          IFEND;

        = osc$i_await_unspecified_event =
          null_list := FALSE;
          IF task_has_gone_ready THEN
            exit_on_ready_task := TRUE;
            exit_save_activity_index := activity;
          IFEND;

        ELSE
          osp$set_status_condition (ose$incorrect_activity, await_status);
        CASEND;

        IF NOT await_complete AND await_status.normal THEN
          activity := activity + 1;
        IFEND;
      WHILEND;

      IF await_status.normal THEN

        IF await_complete THEN { this will exit the repeat loop
          ready_index := activity;
          complete := TRUE;

        ELSEIF exit_on_ready_task THEN { this will exit the repeat loop
          await_complete := TRUE;
          complete := TRUE;
          ready_index := exit_save_activity_index;

        ELSEIF null_list THEN
          ready_index := 1;
          await_complete := TRUE;
          complete := TRUE;

        ELSE
          IF ((wait_time - elapsed_time) > 0) THEN
            start_time := #FREE_RUNNING_CLOCK (local_clock);
            pmp$long_term_wait ((wait_time - elapsed_time) DIV 1000, (wait_time - elapsed_time) DIV 1000);
            current_time := #FREE_RUNNING_CLOCK (local_clock);
            IF current_time > start_time THEN
              elapsed_time := elapsed_time + (current_time - start_time);
            IFEND;
          IFEND;
          task_has_gone_ready := TRUE;
        IFEND;
      IFEND;
    UNTIL await_complete OR NOT await_status.normal;

    cleanup_active_waits;

    IF NOT await_status.normal THEN
      status := await_status;

{ If status is abnormal, return with the ready index of the item in the waitlist that failed.
{ This is for debugging purposes only - callers should not rely on this side effect being true.

      ready_index := activity;
    IFEND;
    osp$disestablish_cond_handler;
  PROCEND osp$i_await_activity;
MODEND osm$i_await_activity;
