?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE: Program Management - activity wait routines', EJECT ??
MODULE osm$await_activity;

{ PURPOSE:
{   The purpose of this request is to support the osp$await_activity_completion
{   request.
{
{ DESIGN:
{   The procedure contained in this module has an execution bracket
{   of 1, 3 and a call bracket of 13.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc osd$virtual_address
*copyc osd$wait
*copyc ose$await_activity_exceptions
*copyc oss$job_paged_literal
*copyc ost$caller_identifier
*copyc ost$hardware_subranges
*copyc ost$status
*copyc pmd$local_queues
*copyc pme$local_queue_exceptions
*copyc pmt$task_id
?? POP ??
*copyc osp$disestablish_cond_handler
*copyc osp$establish_condition_handler
*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
?? NEWTITLE := '[XDCL, #GATE] osp$await_activity', EJECT ??
*copy osh$await_activity

  PROCEDURE [XDCL, #GATE] osp$await_activity
    (    wait_list: ost$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,
      await_status: ost$status,
      current_time: ost$free_running_clock,
      elapsed_time: ost$free_running_clock,
      ignore_status: ost$status,
      null_list: boolean,
      requestor: ost$caller_identifier,
      start_time: ost$free_running_clock,
      wait_time: ost$free_running_clock;

?? NEWTITLE := 'condition_handler', EJECT ??

    PROCEDURE condition_handler
      (    condition: pmt$condition;
           condition_information_p: ^pmt$condition_information;
           stack_frame_save_area_p: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      CASE condition.selector OF
      = pmc$block_exit_processing =
        remove_await_nonempty_queue (1, UPPERBOUND (wait_list));

      = ifc$interactive_condition, jmc$job_resource_condition =
        pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
        EXIT osp$await_activity;

      ELSE
        pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
      CASEND;
    PROCEND condition_handler;
?? OLDTITLE ??
?? NEWTITLE := 'remove_await_nonempty_queue', EJECT ??

    PROCEDURE 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$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;
    osp$establish_condition_handler (^condition_handler, {block_exit} TRUE);
    await_status.normal := TRUE;
    wait_time := UPPERVALUE (ost$free_running_clock);
    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$null_activity =
          ;

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

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

        = pmc$await_local_queue_message =
          null_list := FALSE;
          pmp$await_nonempty_queue (wait_list [activity].qid, requestor.ring, await_complete, await_status);
          IF await_status.normal THEN
            complete := await_complete;
          ELSE
            remove_await_nonempty_queue (1, (activity - 1));
          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
          ready_index := activity;
          remove_await_nonempty_queue (1, UPPERBOUND (wait_list));
        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;
        IFEND;
      IFEND;
    UNTIL await_complete OR NOT await_status.normal;

    osp$disestablish_cond_handler;
    IF await_status.normal THEN
      status.normal := TRUE;
    ELSE
      status := await_status;
    IFEND;
  PROCEND osp$await_activity;
?? OLDTITLE ??
MODEND osm$await_activity;
