?? RIGHT := 110 ??
?? TITLE := 'MMM$IO_REQUEST_PROCESSOR - monitor i/o request handler.' ??
MODULE mmm$io_request_processor;

?? PUSH (LISTEXT := ON) ??
*copyc dfe$error_condition_codes
*copyc dmt$chapter_info
*copyc gft$locked_file_desc_entry_p
*copyc ioe$st_errors
*copyc jmt$initiated_job_list_entry
*copyc mme$condition_codes
*copyc mmk$job_mode_keypoints
*copyc mmk$monitor_mode_keypoints
*copyc mmt$active_segment_table
*copyc mmt$io_control_block
*copyc mmt$io_identifier
*copyc mmt$iocb_index
*copyc mmt$page_frame_index
*copyc mmt$rb_memory_manager_io
*copyc mmt$segment_descriptor_table
*copyc mmt$segment_descriptor_table_ex
*copyc ost$execution_control_block
*copyc ost$cpu_state_table
*copyc osv$page_size
?? POP ??
?? NEWTITLE := '  External procedures' ??

{ External procedures used by this module.

*copyc gfp$mtr_get_fde_p
*copyc jmp$unlock_ajl
*copyc jsp$io_complete
*copyc mmp$convert_pva
*copyc mmp$mm_write_modified_pages
*copyc mmp$page_pull
*copyc mmp$page_pull_hash_sva
*copyc mmp$relink_page_frame
*copyc mmp$remove_pages_working_set
*copyc mmp$verify_pva
*copyc mtp$error_stop
*copyc mtp$set_status_abnormal
*copyc tmp$cause_task_switch
*copyc tmp$get_xcb_p
*copyc tmp$queue_task
*copyc tmp$reissue_monitor_request
*copyc tmp$set_task_ready_uncond
*copyc tmp$set_task_wait
*copyc jmv$ijl_p
*copyc mmv$pft_p
*copyc mmv$pt_p
*copyc mmt$page_pull_status
*copyc mmt$write_modified_pages_status
*copyc mmh$io_control_block

  VAR
    mmv$disable_write_for_perf_meas: [XDCL, #GATE] boolean := FALSE;

?? OLDTITLE, NEWTITLE := '  MMP$MTR_READ_WRITE_IO', EJECT ??

  PROCEDURE [XDCL] mmp$mtr_read_write_io
    (VAR rb: mmt$rb_memory_manager_io;
         cst_p: ^ost$cpu_state_table);

    VAR
      io_id: mmt$io_identifier;

*if $true(osv$generate_keypoint_code)
    #KEYPOINT (osk$entry, $INTEGER (rb.sub_reqcode) * osk$m, mmk$mtr_read_write_io);
*ifend

  /request_proc/
    BEGIN

      CASE rb.sub_reqcode OF
      = mmc$iorc_read_pages =
        IF rb.waitopt = osc$wait THEN
          io_id.specified := TRUE;
          io_id.io_function := ioc$read_page;
          io_id.iocb_index := 0;
          io_id.taskid := cst_p^.xcb_p^.global_task_id;
        ELSE
          io_id.io_function := ioc$read_page;
          mmp$find_iocb_entry (cst_p, io_id, rb.status);
          IF NOT rb.status.normal THEN
            EXIT /request_proc/;
          IFEND;
        IFEND;

        mmp$mtr_read (rb, cst_p, io_id);

      = mmc$iorc_write_pages =

        { MMV$DISABLE_WRITE_FOR_PERF_MEAS will only be set to TRUE for
        { performance measurements. It eliminates the WRITE overhead.

        IF mmv$disable_write_for_perf_meas THEN
          rb.status.normal := FALSE;
          rb.status.condition := mme$write_status_complete;
          RETURN;
        IFEND;

        IF rb.waitopt = osc$wait THEN
          io_id.specified := TRUE;
          io_id.io_function := ioc$write_page;
          io_id.iocb_index := 0;
          io_id.taskid := cst_p^.xcb_p^.global_task_id;
        ELSE
          io_id.io_function := ioc$write_page;
          mmp$find_iocb_entry (cst_p, io_id, rb.status);
          IF NOT rb.status.normal THEN
            EXIT /request_proc/;
          IFEND;
        IFEND;

        mmp$mtr_write (rb, cst_p, io_id);

      = mmc$iorc_await_io_completion =
        mmp$wait_for_any_completion (rb, cst_p);

      CASEND;

    END /request_proc/;

*if $true(osv$generate_keypoint_code)
    #KEYPOINT (osk$exit, 0, mmk$mtr_read_write_io);
*ifend

  PROCEND mmp$mtr_read_write_io;
?? OLDTITLE, NEWTITLE := '  MMP$FIND_IOCB_ENTRY', EJECT ??

{ The purpose of this procedure is to find an available entry in the
{ iocb or return a nil-table or full-table condition.

  PROCEDURE mmp$find_iocb_entry
    (    cst_p: ^ost$cpu_state_table;
     VAR io_id: mmt$io_identifier;
     VAR status: syt$monitor_status);

    VAR
      iocb_index: mmt$iocb_index,
      iocb_ptr: ^mmt$io_control_block;

    status.normal := TRUE;

    iocb_ptr := #ADDRESS (1, #SEGMENT (cst_p^.xcb_p), #OFFSET (cst_p^.xcb_p^.iocb_p));

    IF cst_p^.xcb_p^.iocb_p = NIL THEN
      mtp$set_status_abnormal ('MM', mme$nil_io_control_block, status);
      RETURN;
    IFEND;

{ Check if the table is full--return index of open entry in the io_id.

    FOR iocb_index := LOWERBOUND (iocb_ptr^.iocb_table) TO UPPERBOUND (iocb_ptr^.iocb_table) DO
      IF (NOT iocb_ptr^.iocb_table [iocb_index].used_for_asynchronous_io) AND
            (iocb_ptr^.iocb_table [iocb_index].active_io_count = 0) THEN
        io_id.specified := TRUE;
        io_id.iocb_index := iocb_index;
        io_id.taskid := cst_p^.xcb_p^.global_task_id;
        IF iocb_index > iocb_ptr^.maximum_iocb_index_in_use THEN
          iocb_ptr^.maximum_iocb_index_in_use := iocb_index;
        IFEND;
        RETURN;
      IFEND;
    FOREND;

{ If an index was not RETURNED above, then the table is full.

    mtp$set_status_abnormal ('MM', mme$full_io_control_block, status);

  PROCEND mmp$find_iocb_entry;
?? OLDTITLE, NEWTITLE := '  MMP$MTR_READ', EJECT ??

  PROCEDURE mmp$mtr_read
    (VAR rb: mmt$rb_memory_manager_io;
         cst_p: ^ost$cpu_state_table;
         io_id: mmt$io_identifier);


    VAR
      all_pages_in_memory: boolean,
      aste_p: ^mmt$active_segment_table_entry,
      chapter_info: dmt$chapter_info,
      fde_p: gft$locked_file_desc_entry_p,
      ijle_p: ^jmt$initiated_job_list_entry,
      iocb_ptr: ^mmt$io_control_block,
      locked_page_encountered: boolean,
      locked_page_pfti: mmt$page_frame_index,
      page_count: integer,
      page_in_count: mmt$page_frame_index,
      pfti: mmt$page_frame_index,
      pstatus: mmt$page_pull_status,
      ste_p: ^mmt$segment_descriptor,
      stxe_p: ^mmt$segment_descriptor_extended,
      sva: ost$system_virtual_address;

    rb.status.normal := TRUE;

    all_pages_in_memory := TRUE;
    locked_page_encountered := FALSE;

    ijle_p := cst_p^.ijle_p;
    iocb_ptr := #ADDRESS (1, #SEGMENT (cst_p^.xcb_p), #OFFSET (cst_p^.xcb_p^.iocb_p));

    mmp$verify_pva (^rb.pva, mmc$sat_read_or_write, rb.status);
    IF NOT rb.status.normal THEN
      RETURN;
    IFEND;
    mmp$convert_pva (rb.pva, cst_p, sva, fde_p, aste_p, ste_p, stxe_p);
    IF stxe_p^.access_state <> mmc$sas_allow_access THEN
      IF stxe_p^.access_state = mmc$sas_inhibit_access THEN
        mtp$set_status_abnormal ('MM', mme$volume_unavailable, rb.status);
        RETURN;
      ELSEIF stxe_p^.access_state = mmc$sas_terminate_access THEN
        mtp$set_status_abnormal ('DF', dfe$server_has_terminated, rb.status);
        RETURN;
      IFEND;
    IFEND;

    page_count := (#OFFSET (rb.pva) + rb.length - 1) DIV osv$page_size - (#OFFSET (rb.pva) DIV
          osv$page_size) + 1;

  /pages_in/
    WHILE TRUE DO
      mmp$page_pull_hash_sva (sva, aste_p, page_in_count, pstatus, pfti);
      IF page_in_count = 0 THEN {if not in the page table, call page_pull
        mmp$page_pull (sva, fde_p, cst_p, aste_p, stxe_p, io_id, page_count, ioc$read_page, TRUE,
              page_in_count, pstatus, pfti);
      IFEND;
      CASE pstatus OF
      = ps_found_in_avail, ps_found_in_avail_modified, ps_valid_in_pt, ps_new_page_assigned =
        ;

      = ps_found_on_disk, ps_found_on_server, ps_allocate_required_on_server =
        IF all_pages_in_memory THEN
          all_pages_in_memory := FALSE;
          IF io_id.iocb_index <> 0 THEN
            iocb_ptr^.iocb_table [io_id.iocb_index].iostatus_p := rb.stat_p;
            iocb_ptr^.iocb_table [io_id.iocb_index].used_for_asynchronous_io := TRUE;
            iocb_ptr^.iocb_table [io_id.iocb_index].pva := rb.pva;
            iocb_ptr^.iocb_table [io_id.iocb_index].length := rb.length;
            iocb_ptr^.iocb_table [io_id.iocb_index].sub_reqcode := rb.sub_reqcode;
          IFEND;
        IFEND;
        IF io_id.iocb_index = 0 THEN
          rb.active_io_count := rb.active_io_count + 1;
          ijle_p^.inhibit_swap_count := ijle_p^.inhibit_swap_count + 1;
        ELSE
          iocb_ptr^.iocb_table [io_id.iocb_index].active_io_count :=
                iocb_ptr^.iocb_table [io_id.iocb_index].active_io_count + 1;
          ijle_p^.inhibit_swap_count := ijle_p^.inhibit_swap_count + 1;
        IFEND;

      = ps_no_memory, ps_low_on_memory, ps_pt_full, ps_io_temp_reject, ps_job_work_required =
        cst_p^.dispatch_control.asynchronous_interrupts_pending := TRUE;
        tmp$reissue_monitor_request;
        IF rb.waitopt = osc$nowait THEN
          iocb_ptr^.iocb_table [io_id.iocb_index].used_for_asynchronous_io := FALSE;
          IF iocb_ptr^.iocb_table [io_id.iocb_index].active_io_count > 0 THEN
            tmp$set_task_wait (tmc$ts_io_wait_not_queued);
          ELSE
            tmp$cause_task_switch;
          IFEND;
        ELSE {wait was specified}
          IF rb.active_io_count > 0 THEN
            tmp$set_task_wait (tmc$ts_io_wait_not_queued);
          ELSE
            tmp$cause_task_switch;
          IFEND;
        IFEND;
        RETURN;

      = ps_locked =
        locked_page_encountered := TRUE;
        locked_page_pfti := pfti;

      = ps_read_beyond_eoi =
        mtp$set_status_abnormal ('MM', mme$read_beyond_eoi, rb.status);
        RETURN;

      = ps_beyond_file_limit =
        mtp$set_status_abnormal ('MM', mme$read_write_beyond_msl, rb.status);
        RETURN;

      = ps_no_extend_permission =
        mtp$set_status_abnormal ('MM', mme$write_beyond_eoi_no_append, rb.status);
        RETURN;

      = ps_done =
        mtp$error_stop ('mm - internal error');
        RETURN;

      = ps_volume_unavailable =
        mtp$set_status_abnormal ('MM', mme$volume_unavailable, rb.status);
        RETURN;

      = ps_server_terminated =
        mtp$set_status_abnormal ('DF', dfe$server_has_terminated, rb.status);
        RETURN;

      ELSE
      CASEND;
      page_count := page_count - page_in_count;
      IF page_count > 0 THEN
        sva.offset := sva.offset + (page_in_count * osv$page_size);
      ELSE
        EXIT /pages_in/;
      IFEND;
    WHILEND /pages_in/;

    IF locked_page_encountered THEN
      IF rb.waitopt = osc$wait THEN
        tmp$reissue_monitor_request;
        IF rb.active_io_count > 0 THEN
          tmp$set_task_wait (tmc$ts_io_wait_not_queued);
        ELSE
          tmp$queue_task (cst_p^.taskid, tmc$ts_io_wait_queued, mmv$pft_p^ [locked_page_pfti].task_queue);
          cst_p^.xcb_p^.page_wait_info.pva := NIL;
        IFEND;
      ELSE {nowait}
        iocb_ptr^.iocb_table [io_id.iocb_index].io_already_active := TRUE;
        IF iocb_ptr^.iocb_table [io_id.iocb_index].active_io_count = 0 THEN
{Make an iocb entry; check will find io_already_active and will repeat the request to get the condition.
          iocb_ptr^.iocb_table [io_id.iocb_index].condition := 0;
          iocb_ptr^.iocb_table [io_id.iocb_index].iostatus_p := rb.stat_p;
          iocb_ptr^.iocb_table [io_id.iocb_index].used_for_asynchronous_io := TRUE;
          iocb_ptr^.iocb_table [io_id.iocb_index].pva := rb.pva;
          iocb_ptr^.iocb_table [io_id.iocb_index].length := rb.length;
          iocb_ptr^.iocb_table [io_id.iocb_index].sub_reqcode := mmc$iorc_read_pages;
        IFEND;
      IFEND;
    ELSEIF all_pages_in_memory THEN
      mtp$set_status_abnormal ('MM', mme$page_found_in_memory, rb.status);
    ELSEIF rb.waitopt = osc$wait THEN
{There are pages on disk, so wait for the io request to complete.
      tmp$set_task_wait (tmc$ts_io_wait_not_queued);
    IFEND;
  PROCEND mmp$mtr_read;
?? OLDTITLE, NEWTITLE := '  MMP$MTR_WRITE', EJECT ??

  PROCEDURE mmp$mtr_write
    (VAR rb: mmt$rb_memory_manager_io;
         cst_p: ^ost$cpu_state_table;
         io_id: mmt$io_identifier);

    VAR
      active_io_count: mmt$active_io_count,
      aste_p: ^mmt$active_segment_table_entry,
      fde_p: gft$locked_file_desc_entry_p,
      ijle_p: ^jmt$initiated_job_list_entry,
      io_already_active: boolean,
      iocb_ptr: ^mmt$io_control_block,
      last_written_pfti: mmt$page_frame_index,
      page_count: integer,
      status: syt$monitor_status,
      ste_p: ^mmt$segment_descriptor,
      stxe_p: ^mmt$segment_descriptor_extended,
      sva: ost$system_virtual_address,
      write_status: mmt$write_modified_pages_status;

    rb.status.normal := TRUE;
    active_io_count := 0;
    io_already_active := FALSE;

    ijle_p := cst_p^.ijle_p;
    iocb_ptr := #ADDRESS (1, #SEGMENT (cst_p^.xcb_p), #OFFSET (cst_p^.xcb_p^.iocb_p));

    mmp$verify_pva (^rb.pva, mmc$sat_read_or_write, rb.status);
    IF NOT rb.status.normal THEN
      RETURN;
    IFEND;
    mmp$convert_pva (rb.pva, cst_p, sva, fde_p, aste_p, ste_p, stxe_p);

    IF (aste_p^.queue_id <> mmc$pq_job_working_set) AND ((aste_p^.queue_id < mmc$pq_shared_first) OR
          (aste_p^.queue_id > mmc$pq_shared_last)) THEN
      mtp$set_status_abnormal ('MM', mme$segment_not_pageable, rb.status);
      RETURN;
    IFEND;

    IF fde_p^.media = gfc$fm_transient_segment THEN
      mtp$set_status_abnormal ('MM', mme$segment_not_assigned_device, rb.status);
      RETURN;
    IFEND;

    mmp$mm_write_modified_pages (sva, rb.length, fde_p, aste_p, ioc$write_page, rb.init_new_io, FALSE, io_id,
          active_io_count, io_already_active, last_written_pfti, write_status);

    CASE write_status OF
    = mmc$wmp_io_complete =
      IF io_already_active THEN
        IF io_id.iocb_index = 0 THEN
          IF mmv$pft_p^ [last_written_pfti].active_io_count = 0 THEN
            mtp$error_stop ('MM - WMP tried to queue and no IO');
          IFEND;
          tmp$queue_task (cst_p^.taskid, tmc$ts_page_wait, mmv$pft_p^ [last_written_pfti].task_queue);
          rb.init_new_io := FALSE;
          tmp$reissue_monitor_request;
        ELSE {nowait--make IOCB entry that looks complete, but set io_already_active
          iocb_ptr^.iocb_table [io_id.iocb_index].pva := rb.pva;
          iocb_ptr^.iocb_table [io_id.iocb_index].length := rb.length;
          iocb_ptr^.iocb_table [io_id.iocb_index].iostatus_p := rb.stat_p;
          iocb_ptr^.iocb_table [io_id.iocb_index].sub_reqcode := mmc$iorc_write_pages;
          iocb_ptr^.iocb_table [io_id.iocb_index].used_for_asynchronous_io := TRUE;
          iocb_ptr^.iocb_table [io_id.iocb_index].active_io_count := 0;
          iocb_ptr^.iocb_table [io_id.iocb_index].io_already_active := TRUE;
        IFEND;
      ELSE
        mtp$set_status_abnormal ('MM', mme$write_status_complete, rb.status);
      IFEND;

    = mmc$wmp_io_active =
      IF io_id.iocb_index = 0 THEN
        IF io_already_active THEN
{ Reissue the request to check the condition of the io that was already active.
          rb.init_new_io := FALSE;
          tmp$reissue_monitor_request;
        IFEND;
        rb.active_io_count := active_io_count;
        ijle_p^.inhibit_swap_count := ijle_p^.inhibit_swap_count + active_io_count;
        tmp$set_task_wait (tmc$ts_io_wait_not_queued);
      ELSE
{ Make a full iocb entry because the write may have to be called again via R3--mmp$process_io_completions.
        iocb_ptr^.iocb_table [io_id.iocb_index].pva := rb.pva;
        iocb_ptr^.iocb_table [io_id.iocb_index].length := rb.length;
        iocb_ptr^.iocb_table [io_id.iocb_index].iostatus_p := rb.stat_p;
        iocb_ptr^.iocb_table [io_id.iocb_index].sub_reqcode := mmc$iorc_write_pages;
        iocb_ptr^.iocb_table [io_id.iocb_index].used_for_asynchronous_io := TRUE;
        iocb_ptr^.iocb_table [io_id.iocb_index].io_already_active := io_already_active;
        iocb_ptr^.iocb_table [io_id.iocb_index].active_io_count := active_io_count;
        ijle_p^.inhibit_swap_count := ijle_p^.inhibit_swap_count + active_io_count;
      IFEND;

    = mmc$wmp_io_initiation_reject =
      tmp$reissue_monitor_request;
      IF active_io_count > 0 THEN
        IF io_id.iocb_index = 0 THEN
          rb.active_io_count := active_io_count;
          ijle_p^.inhibit_swap_count := ijle_p^.inhibit_swap_count + active_io_count;
        ELSE
{ Only need .used_for_asynchronous_io and .active_io_count in the iocb, because those are the fields used
{ by mmp$mtr_process_io_completions to set the task ready.  The request has been reissued.
          iocb_ptr^.iocb_table [io_id.iocb_index].used_for_asynchronous_io := FALSE;
          iocb_ptr^.iocb_table [io_id.iocb_index].active_io_count := active_io_count;
          ijle_p^.inhibit_swap_count := ijle_p^.inhibit_swap_count + active_io_count;
        IFEND;
        tmp$set_task_wait (tmc$ts_io_wait_not_queued);
      ELSE
        tmp$cause_task_switch;
      IFEND;

    = mmc$wmp_io_errors =
      IF active_io_count = 0 THEN
        mtp$set_status_abnormal ('MM', ioc$disk_media_error, rb.status);
      ELSE
        IF io_id.iocb_index = 0 THEN
          rb.condition := ioc$disk_media_error;
          rb.active_io_count := active_io_count;
          ijle_p^.inhibit_swap_count := ijle_p^.inhibit_swap_count + active_io_count;
          tmp$set_task_wait (tmc$ts_io_wait_not_queued);
        ELSE
{ Need a full iocb entry; the write may be called again after file space reallocation.
          iocb_ptr^.iocb_table [io_id.iocb_index].pva := rb.pva;
          iocb_ptr^.iocb_table [io_id.iocb_index].length := rb.length;
          iocb_ptr^.iocb_table [io_id.iocb_index].iostatus_p := rb.stat_p;
          iocb_ptr^.iocb_table [io_id.iocb_index].io_already_active := io_already_active;
          iocb_ptr^.iocb_table [io_id.iocb_index].sub_reqcode := mmc$iorc_write_pages;
          iocb_ptr^.iocb_table [io_id.iocb_index].used_for_asynchronous_io := TRUE;
          iocb_ptr^.iocb_table [io_id.iocb_index].condition := ioc$disk_media_error;
          iocb_ptr^.iocb_table [io_id.iocb_index].active_io_count := active_io_count;
          ijle_p^.inhibit_swap_count := ijle_p^.inhibit_swap_count + active_io_count;
        IFEND;
      IFEND;
    = mmc$wmp_volume_unavailable =
      mtp$set_status_abnormal ('MM', mme$volume_unavailable, rb.status);
    = mmc$wmp_server_terminated =
      mtp$set_status_abnormal ('DF', dfe$server_has_terminated, rb.status);
    CASEND;

    IF rb.remove_pages THEN
      mmp$remove_pages_working_set (sva, rb.length, aste_p, page_count);
    IFEND;

  PROCEND mmp$mtr_write;
?? OLDTITLE, NEWTITLE := '  MMP$MTR_PROCESS_IO_COMPLETION', EJECT ??

  PROCEDURE [XDCL] mmp$mtr_process_io_completion
    (    io_id: mmt$io_identifier;
         io_function: iot$io_function;
         io_status: syt$monitor_status);

    VAR
      ijle_p: ^jmt$initiated_job_list_entry,
      iocb_ptr: ^mmt$io_control_block,
      need_to_ready_task: boolean,
      reset_completion_time: boolean,
      rb_p: ^mmt$rb_memory_manager_io,
      xcb_p: ^ost$execution_control_block;


    need_to_ready_task := FALSE;
    reset_completion_time := FALSE;

    tmp$get_xcb_p (io_id.taskid, xcb_p, ijle_p);
    IF xcb_p = NIL THEN
      mtp$error_stop ('MM - IO complete on swapped job');
    IFEND;

    IF io_id.iocb_index = 0 THEN
      rb_p := #LOC (xcb_p^.xp.x_registers [0]);
      IF rb_p^.condition = 0 THEN
        rb_p^.condition := io_status.condition;
      IFEND;
      rb_p^.active_io_count := rb_p^.active_io_count - 1;
      ijle_p^.inhibit_swap_count := ijle_p^.inhibit_swap_count - 1;
      IF rb_p^.active_io_count = 0 THEN
        need_to_ready_task := TRUE;
      IFEND;
    ELSE
      iocb_ptr := #ADDRESS (1, #SEGMENT (xcb_p), #OFFSET (xcb_p^.iocb_p));
      IF iocb_ptr^.iocb_table [io_id.iocb_index].condition = 0 THEN
        iocb_ptr^.iocb_table [io_id.iocb_index].condition := io_status.condition;
      IFEND;
      IF iocb_ptr^.iocb_table [io_id.iocb_index].active_io_count = 1 THEN
        { If the active io count is 1, then all io for this request is completed.  We check for a count
        { of 1 rather than 0 because we don't decrement the count until the end of this procedure.  We
        { don't decrement the count until we are done checking and changing the table here in order to
        { prevent a dual cpu timing problem in which a task running on the other cpu checks the table,
        { sees an active_io_count of 0 (which indicates all io for the request has finished), and then
        { changes the table before we are done processing here.  (This can happen if the proceesor
        { executing this code exchanges to NOS.)

        IF NOT iocb_ptr^.iocb_table [io_id.iocb_index].used_for_asynchronous_io THEN
          iocb_ptr^.iocb_table [io_id.iocb_index].iostatus_p := NIL;
          iocb_ptr^.iocb_table [io_id.iocb_index].condition := 0;
          iocb_ptr^.iocb_table [io_id.iocb_index].io_already_active := FALSE;
          need_to_ready_task := TRUE;
        ELSEIF iocb_ptr^.wait_for_any_completion THEN
          iocb_ptr^.wait_for_any_completion := FALSE;
          need_to_ready_task := TRUE;
        IFEND;
        reset_completion_time := TRUE;
      IFEND;
      iocb_ptr^.iocb_table [io_id.iocb_index].active_io_count :=
            iocb_ptr^.iocb_table [io_id.iocb_index].active_io_count - 1;
      ijle_p^.inhibit_swap_count := ijle_p^.inhibit_swap_count - 1;
      IF reset_completion_time THEN
        iocb_ptr^.latest_completion_time := #FREE_RUNNING_CLOCK (0);
      IFEND;
    IFEND;

    jmp$unlock_ajl (ijle_p);

    IF need_to_ready_task THEN
      tmp$set_task_ready_uncond (io_id.taskid, tmc$ts_io_wait_not_queued);
    IFEND;

    IF (ijle_p^.inhibit_swap_count = 0) AND (ijle_p^.notify_swapper_when_io_complete) THEN
      jsp$io_complete (ijle_p);
    IFEND;

  PROCEND mmp$mtr_process_io_completion;
?? OLDTITLE, NEWTITLE := '  MMP$WAIT_FOR_ANY_COMPLETION', EJECT ??

  PROCEDURE mmp$wait_for_any_completion
    (    rb: mmt$rb_memory_manager_io;
         cst_p: ^ost$cpu_state_table);

    VAR
      iocb_ptr: ^mmt$io_control_block;

    iocb_ptr := #ADDRESS (1, #SEGMENT (cst_p^.xcb_p), #OFFSET (cst_p^.xcb_p^.iocb_p));
    IF rb.latest_completion_time = iocb_ptr^.latest_completion_time THEN
      iocb_ptr^.wait_for_any_completion := TRUE;
      tmp$set_task_wait (tmc$ts_io_wait_not_queued);
    IFEND;

  PROCEND mmp$wait_for_any_completion;
?? OLDTITLE, OLDTITLE ??
MODEND mmm$io_request_processor;
