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

{   PURPOSE:
{     The purpose of this request is to support the osp$f1_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 oss$job_paged_literal
*copyc nac$null_connection_id
*copyc osd$virtual_address
*copyc ame$improper_file_id
*copyc nae$sk_socket_layer
*copyc ose$await_activity_exceptions
*copyc ost$f1_wait
*copyc ost$hardware_subranges
*copyc ost$status
?? POP ??
*copyc baf$task_file_entry_p
*copyc nap$check_data_available
*copyc nap$remove_wait_data_available
*copyc nlp$sk_lock_job_socket
*copyc nlp$sk_tcp_await_data_available
*copyc nlp$sk_tcp_check_accept_socket
*copyc nlp$sk_tcp_remove_accept_socket
*copyc nlp$sk_tcp_remove_data_avail
*copyc nlp$sk_unlock_job_socket
*copyc nlp$udp_await_data_available
*copyc nlp$udp_remove_data_available
*copyc osp$append_status_integer
*copyc osp$disestablish_cond_handler
*copyc osp$establish_condition_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$continue_to_cause
*copyc pmp$long_term_wait
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] OSP$F1_AWAIT_ACTIVITY', EJECT ??

  PROCEDURE [XDCL, #GATE] osp$f1_await_activity
    (    wait_list: ost$f1_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
      activity: activity_index,
      await_complete: boolean,
      current_time: ost$free_running_clock,
      elapsed_time: ost$free_running_clock,
      exit_on_ready_task: boolean,
      exit_save_activity_index: activity_index,
      inhibit_job_recovery_pushed: boolean,
      job_socket: ^nat$sk_job_socket,
      null_list: boolean,
      start_time: ost$free_running_clock,
      task_has_gone_ready: boolean,
      wait_time: ost$free_running_clock;

?? NEWTITLE := 'P$REMOVE_NETWORK_WAITS', EJECT ??

    PROCEDURE p$remove_network_waits;

{ The purpose of this request is to remove the current task from all network wait queues.

      VAR
        connection_id: nat$connection_id,
        file_instance: ^bat$task_file_entry,
        index: integer,
        job_socket: ^nat$sk_job_socket;

      index := 1;

      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;

      WHILE index <= UPPERBOUND (wait_list) DO
        CASE wait_list [index].activity OF
        = osc$f1_null_activity, osc$f1_await_time, nac$f1_await_activity_status =

        = nac$f1_await_data_available =
          file_instance := baf$task_file_entry_p (wait_list [index].file_identifier);
          IF file_instance <> NIL THEN
            IF file_instance^.device_class = rmc$network_device THEN
              nap$remove_wait_data_available (wait_list [index].file_identifier);
            ELSEIF file_instance^.device_class = rmc$terminal_device THEN
              IF file_instance^.st_open_file_dsc_pointer <> NIL THEN
                nap$remove_wait_data_available (file_instance^.st_open_file_dsc_pointer^.vtp_file_id);
              IFEND;
            IFEND;
          IFEND;

        = osc$f1_await_unspecified_event =
          ;
        = nac$f1_sk_await_data_available =
          nlp$sk_lock_job_socket (wait_list [index].socket_id, job_socket);
          IF (job_socket <> NIL) AND (job_socket^.status = nac$sk_socket_open) THEN
            IF job_socket^.socket_type = nac$sk_udp_socket THEN
              nlp$udp_remove_data_available (job_socket^.global_socket_id);
            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_remove_data_avail (job_socket^.connection_id);
              ELSEIF job_socket^.tcp_socket_type = nlc$tcp_listen_socket THEN
                nlp$sk_tcp_remove_accept_socket (job_socket^.application, job_socket^.port,
                      job_socket^.bound_address);
              IFEND;
            IFEND;
          IFEND;
          nlp$sk_unlock_job_socket (wait_list [index].socket_id);

        CASEND;

        index := index + 1;
      WHILEND;

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

    PROCEND p$remove_network_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$f1_await_activity; {----->
      = pmc$block_exit_processing =
        p$remove_network_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 ??
?? EJECT ??

    status.normal := TRUE;
    elapsed_time := 0;
    complete := FALSE;
    wait_time := UPPERVALUE (ost$free_running_clock);
    task_has_gone_ready := FALSE;
    exit_on_ready_task := FALSE;
    null_list := TRUE;

    inhibit_job_recovery_pushed := FALSE;
    #SPOIL (inhibit_job_recovery_pushed);

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

    REPEAT
      await_complete := FALSE;
      activity := 1;
      WHILE NOT await_complete AND (activity <= osc$f1_wait_list_size) AND status.normal DO
        CASE wait_list [activity].activity OF
        = osc$f1_null_activity =
          ;
        = osc$f1_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;

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

        = nac$f1_await_data_available =
          null_list := FALSE;
          nap$check_data_available (wait_list [activity].file_identifier, await_complete, status);

        = nac$f1_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

            { We can set here await_complete to true, as it's reset in the nlp requests to false and in all
            { other cases we wanna return true

            await_complete := TRUE;
            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);
                IFEND;
              IFEND;
            IFEND;
          ELSE { Unknown Socket
            osp$set_status_abnormal (nac$status_id, nae$sk_unknown_socket, '', status);
            osp$append_status_integer (osc$status_parameter_delimiter, wait_list [activity].socket_id, 10,
                  TRUE, 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);

        = osc$f1_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, status);
        CASEND;

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

      IF 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;
      ELSE

{ 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;
    UNTIL await_complete OR NOT status.normal;

    p$remove_network_waits;

    osp$disestablish_cond_handler;

  PROCEND osp$f1_await_activity;
?? OLDTITLE ??
MODEND osm$f1_await_activity;
