1 /****^  ***********************************************************
   2         *                                                         *
   3         * Copyright, (C) Honeywell Bull Inc., 1987                *
   4         *                                                         *
   5         * Copyright, (C) Honeywell Information Systems Inc., 1982 *
   6         *                                                         *
   7         *********************************************************** */
   8 /* format: style2,indcomtxt */
   9 /* use: pl1_macro pc.pl1.pmac  -target l68 */
  10 pc:
  11      procedure;
  12 
  13 /* *      PC -- the utility procedure of pl1 page control.
  14    *
  15    *      Last modified (date and reason):
  16    *
  17    *      1985-03-28, BIM: assume that all modified pages of synch segments
  18    *                  are synch held until proven otherwise by page$pwrite.
  19    *      841220 by Keith Loepere to count dirs pages against its own quota.
  20    *      840623 by Keith Loepere for nullify entry for bce.
  21    *      840417 E. A. Ranzenbach to correct page_read zero event problem that caused crashes in the segment mover.
  22    *      84-01-19 BIM to remove unworkable synch segmove support.
  23    *      84-01-03 BIM to finish segmove.
  24    *      831219 by E. N. Kittlitz, for segmove
  25    *      09/19/83 by E. N. Kittlitz, per UofC SGH, periodically unlock PTL during long flushes.
  26    *      08/22/83 by E. N. Kittlitz, per UofC GM&SGH, don't hedge-write per-process pages.
  27    *      10/27/82 by J. Bongiovanni to reset damaged, fm_damaged on truncate
  28    *               and for synchronized pages
  29    *      08/17/82 by J. Bongiovanni for scavenger
  30    *      06/09/82 by J. Bongiovanni to fix shutdown quota problem
  31    *      03/07/82 by J. Bongiovanni for record stocks
  32    *      01/23/82 by BIM for truncate_count
  33    *      12/29/81 by C. Hornig to remove Page Multilevel and fix fencepost error in flush.
  34    *      08/11/81 by W. Olin Sibert, to fix get_file_map to not report nulled addresses as modified.
  35    *         This fix actually provided by Steve Harris, University of Calgary
  36    *      02/20/81 by W. Olin Sibert, to conditionalize page-multilevel (phase one of ADP conversion)
  37    *      11/17/80 by ENK for new dtu/dtm calculation
  38    *      11/06/80 by ENK for loop_up_fms honouring of aste.gtms.
  39    *      03/16/78 by BSG for phm1, incore null non-reportage.
  40    *      08/01/77 by Greenberg for badd_types, pc_recover_sst.
  41    *      05/03/77 by BSG for page$pcleanup
  42    *      01/27/77 by TVV for non-fatal unprotected addresses
  43    *      11/01/76 by D. Vinograd to add entry for volume dumper which returns special null addresses
  44    *         and does not deposit.
  45    *      10/31/76 by BSG for truncate_deposit_all entry
  46    *      05/13/76 by BSG for seg-by-seg PD flush.
  47    *      04/13/76 by REM for Cleanup Metering
  48    *      10/11/75 by BSG for fault_time_withdraws
  49    *      03/04/75 by BSG for new storage system (incl. no pdht).
  50    *      12/11/74 by BSG for new CME/PTW protocols and new core control.
  51    *      06/19/74 by BSG for page$pwait and page$cam.
  52    *      08/21/73 by RBS to put in checks for reused addresses.
  53    *      08/03/73 by RBS to cause pc$flush to index thru cmes rather than follow threads.
  54    *      08/10/73 by SHW to use 18 bit device addresses
  55    *      07/15/73 by RBS to cause pages that are in core to be written to disk by pd_flush_all
  56    *      10/04/72 by RBS to make page waits go to device control to accomodate bulk store logic
  57    *      06/06/72 by RBS to modify for follow-on
  58    *      10/26/71 by RHG to fix move_page_table for pages which are in core when moved
  59    *      10/07/71 by SHW to add ptwp to pdme (increase entry size to 3 words)
  60    *      10/05/71 by RHG to initialize pdmap and to skip the first sst.nrecs_pdmap entries in pd_flush_all
  61    *      09/22/71 by RHG to make null devadds include a ptr for page
  62    *      09/20/71 by RHG to fix bug in pc$get_file_map which lost all pages of file except first at deactivation
  63    *      09/03/71 by Steve Webber to make calls to page$withdraw be fixed bin(4), not bit(4)
  64    *      08/10/71 by Richard H. Gumpertz to add code for page multi-level
  65 */
  66 
  67           dcl     Astep                  ptr parameter;
  68           dcl     Copy_Astep             ptr parameter;
  69           dcl     File_Mapp              ptr parameter;
  70           dcl     Listp                  ptr parameter;
  71           dcl     Pageno_Listp           ptr parameter;
  72           dcl     Deposit_Count          fixed bin parameter;
  73           dcl     First_Page             fixed bin parameter;
  74           dcl     Last_Page              fixed bin parameter;
  75           dcl     N_Pages                fixed bin parameter;
  76           dcl     N_In_Core              fixed bin parameter;
  77           dcl     Records                fixed bin parameter;
  78           dcl     Pvtx                   fixed bin parameter;
  79           dcl     Vtocx                  fixed bin parameter;
  80           dcl     Move_Astep             pointer parameter;
  81           dcl     Old_Astep              ptr parameter;
  82           dcl     New_Astep              ptr parameter;
  83           dcl     Code                   fixed bin (35) parameter;
  84           dcl     New_Vtocx              fixed bin (17) parameter;
  85           dcl     New_Pvtx               fixed bin (17);
  86 
  87           dcl     (records, first_page, last_page, i)
  88                                          fixed bin;
  89           dcl     ind                    fixed bin (35);
  90           dcl     temp_ind               fixed bin (35);
  91           dcl     pvtx                   fixed bin;
  92           dcl     dumper                 bit (1);
  93           dcl     return_pageno          bit (1) aligned;
  94           dcl     add_to_dmpr_map        bit (1);
  95           dcl     (getfmap_csl, getfmap_np, getfmap_nrec)
  96                                          fixed bin (9);
  97           dcl     offed_sw               bit (1);
  98           dcl     j                      fixed bin;
  99           dcl     segmove_records_used   fixed bin;
 100           dcl     (cmp, ptwp)            ptr;
 101           dcl     curtime                fixed bin (71);
 102           dcl     n_in_core              fixed bin (18);
 103           dcl     n_io_started           fixed bin;
 104           dcl     pageno                 fixed bin;
 105           dcl     (from_core, count)     bit (1);
 106           dcl     (old_astep, new_astep, old_ptp, new_ptp, move_ptp)
 107                                          ptr;
 108           dcl     oldmask                fixed bin (71);
 109           dcl     no_deposit_no_return   bit (1) aligned;
 110           dcl     tr_count_sw            bit (1) aligned;
 111           dcl     segmove_records_needed fixed bin;
 112           dcl     segmove_records_in_hand
 113                                          fixed bin;
 114           dcl     segmove_total_records  fixed bin;
 115           dcl     code                   fixed bin (35);
 116           dcl     new_pvtx               fixed bin;
 117           dcl     new_vtocx              fixed bin;
 118           dcl     move_tries             fixed bin;
 119 
 120           dcl     1 copy_aste            like aste aligned;
 121 
 122           dcl     fword                  (0:99) fixed bin based;
 123 
 124           dcl     Address_Array          (0:255) bit (22) aligned based (Listp);
 125           dcl     (deposit_list, segmove_deposit_list)
 126                                          (0:255) bit (22) aligned;
 127           dcl     rfm                    (0:255) bit (22) aligned;
 128           dcl     1 Devadd_Array         (0:255) aligned based (Listp),
 129                     2 record_no          bit (18) unaligned,
 130                     2 add_type           bit (4) unaligned;
 131           dcl     Pageno_List            (0:255) fixed bin aligned based (Pageno_Listp);
 132           dcl     pageno_list            (0:255) fixed bin aligned;
 133 
 134           dcl     devadd                 bit (22) unaligned;
 135           dcl     devadd_record_no       bit (18) unaligned defined (devadd);
 136           dcl     devadd_record_no_proper
 137                                          bit (17) defined (devadd) pos (2);
 138           dcl     devadd_add_type        bit (4) unaligned defined (devadd) position (19);
 139           dcl     devadd_null_flag       bit (1) defined (devadd) position (1);
 140 
 141 
 142           dcl     1 devadd_bits          unal based (addr (devadd_add_type)) like badd_type;
 143 
 144 
 145           dcl     cleanup_start_time     fixed bin (71);    /* Cleanup Metering */
 146 
 147           dcl     error_table_$bad_arg   fixed bin (35) ext static;
 148           dcl     error_table_$action_not_performed
 149                                          fixed bin (35) ext static;
 150           dcl     error_table_$synch_seg_segmove
 151                                          fixed bin (35) external static;
 152           dcl     dbm_man$set_incr       entry (fixed bin, fixed bin, fixed bin (35));
 153           dcl     (
 154                   lock$lock_fast,
 155                   lock$unlock_fast
 156                   )                      entry (pointer);
 157           dcl     page$cam               ext entry;
 158           dcl     page$deposit_list      entry (fixed bin, ptr, fixed bin, fixed bin, fixed bin, ptr);
 159           dcl     page$pcleanup          entry (ptr, fixed bin);
 160           dcl     page$pread             entry (ptr, fixed bin, fixed bin (35));
 161           dcl     page$pwait             ext entry (fixed bin (35));
 162           dcl     page$pwrite            ext entry (ptr, fixed bin);
 163           dcl     page$withdraw_list     entry (fixed bin, ptr, fixed bin, fixed bin, fixed bin (35), fixed bin (35));
 164           dcl     pmut$lock_ptl          ext entry (fixed bin (71), ptr);
 165           dcl     pmut$unlock_ptl        ext entry (fixed bin (71), ptr);
 166           dcl     pxss$notify            ext entry (fixed bin);
 167           dcl     pxss$relinquish_priority
 168                                          ext entry;
 169           dcl     quotaw$cu_for_pc       entry (ptr, fixed bin, bit (1) aligned);
 170           dcl     syserr                 ext entry options (variable);
 171           dcl     trace                  ext entry options (variable);
 172 
 173           dcl     null_devadd_not_in_core
 174                                          bit (36) aligned internal static options (constant) init ("000000000001"b3);
 175           dcl     line_of_words          char (23) internal static options (constant) init ("^w ^w ^w ^w ^w ^w ^w ^w");
 176           dcl     half_line_of_words     char (11) defined (line_of_words);
 177 
 178           dcl     (addr, addrel, addwordno, bit, clock, divide, fixed, max, min, null, ptr, rel, size, unspec, wordno)
 179                                          builtin;
 180 %page;
 181 cleanup:
 182      entry (Astep);                                         /* Entry to get segment out of core. */
 183                                                             /* Caller guarantees no access to segment */
 184 
 185 /* Note that synchronized pages which are modified and cannot be written yet
 186    are left in memory. If this happens during shutdown, it is fine. Otherwise,
 187    the caller must detect this situation and handle it appropriately. It
 188    can be detected by checking that aste.np is non-zero. */
 189 
 190           sstp = addr (sst_seg$);
 191           astep = Astep;
 192           cmp = sst.cmp;                                    /* get a pointer to the core map */
 193           cleanup_start_time = clock ();                    /* Cleanup Metering */
 194 
 195           sst.cleanup_count = sst.cleanup_count + 1;        /* Cleanup Metering */
 196           call pmut$lock_ptl (oldmask, ptwp);               /* mask */
 197           records = 0;
 198           if pc_trace
 199           then call trace ("cleanup^-^-astep = ^p", astep);
 200 loopc:
 201           ptp = addrel (astep, sst.astsize);                /* get a pointer to the page table */
 202           ind = -1;                                         /* index of page to wait on */
 203           do i = 0 to sst.pts (fixed (aste.ptsi, 2)) - 1;   /* loop over all pages in the segment */
 204                if atptw.core
 205                then do;                                     /* In core, includes all O/S */
 206 
 207                          if ^ptw.os
 208                          then do;                           /* Not out of service */
 209                                    if ^(ptw.phm | ptw.phm1)
 210                                    then /* Attempt to clean up the page */
 211                                         call page$pcleanup (astep, i);
 212                                                             /* Do it, cam the cache */
 213                                                             /* He turns off PTW access, SDW'S gone, so no race. */
 214                                    else call page$pwrite (astep, i);
 215                                                             /* Start a write */
 216                               end;
 217 
 218                          if ptw.os
 219                          then ind = fixed (rel (ptp), 18);  /* Set wait event */
 220 
 221                     end;
 222 
 223                ptp = addrel (ptp, size (ptw));              /* Next ptw, please */
 224           end;
 225 
 226           if ind > 0
 227           then call wait_then_go_to (loopc);
 228 
 229           sst.cleanup_real_time = sst.cleanup_real_time /* Cleanup Metering */ + clock () - cleanup_start_time;
 230                                                             /* Cleanup Metering */
 231 
 232 quit:
 233           call pmut$unlock_ptl (oldmask, ptwp);             /* unlock and unmask */
 234           return;
 235 %page;
 236 nullify:
 237      entry (Astep);                                         /* Entry to nullify a bce/hardcore segment.
 238                                                                Part of disk optimization for bce. */
 239 
 240 /* The idea is to mark the pages of the segment unmodified, clean them up
 241    (to disk) and then mark the disk addresses as null.  This is done just to
 242    optimize the later filling in of this segment.  We don't guarantee perfection
 243    in this, but it doesn't matter.  Anyone who calls this ensures that the
 244    segment is not in use so we don't expect a problem with pages being
 245    referenced between ptl lockings. */
 246 
 247 /* First unmodify the pages.  Note that os pages are not affected, but these
 248    either aren't yet modified (being read) or will become unmodified (after
 249    write). */
 250 
 251           sstp = addr (sst_seg$);
 252           astep = Astep;
 253 
 254           call pmut$lock_ptl (oldmask, ptwp);               /* mask */
 255           ptp = addrel (astep, sst.astsize);                /* get a pointer to the page table */
 256           do i = 0 to sst.pts (fixed (aste.ptsi, 2)) - 1;   /* loop over all pages in the segment */
 257                if atptw.core
 258                then /* In core, includes all O/S */
 259                     if ^ptw.os                              /* Not out of service */
 260                     then ptw.phm, ptw.phm1 = "0"b;
 261 
 262                ptp = addrel (ptp, size (ptw));              /* Next ptw, please */
 263           end;
 264           call pmut$unlock_ptl (oldmask, ptwp);             /* unlock and unmask */
 265 
 266           call cleanup (astep);                             /* free all memory frame; make into disk addresses */
 267 
 268           call pmut$lock_ptl (oldmask, ptwp);               /* mask */
 269           ptp = addrel (astep, sst.astsize);                /* get a pointer to the page table */
 270           do i = 0 to sst.pts (fixed (aste.ptsi, 2)) - 1;   /* loop over all pages in the segment */
 271                if atptw.disk
 272                then substr (ptw.add, 1, 1) = "1"b;          /* make null */
 273 
 274                ptp = addrel (ptp, size (ptw));              /* Next ptw, please */
 275           end;
 276           call pmut$unlock_ptl (oldmask, ptwp);             /* unlock and unmask */
 277           return;
 278 %page;
 279 fill_page_table:
 280      entry (Astep, File_Mapp, N_Pages);
 281 
 282 
 283           astep = Astep;                                    /* Copy args */
 284           fmp = File_Mapp;
 285           pvtx = astep -> aste.pvtx;
 286           last_page = N_Pages - 1;                          /* arg is csl */
 287           sstp = addr (sst_seg$);
 288           records = 0;
 289 
 290           ptp = addrel (astep, sstp -> sst.astsize);
 291           do i = 0 to last_page;
 292                devadd = file_map.fm (i);                    /* No need to lock here */
 293                if devadd_null_flag
 294                then do;                                     /* Outside world null address, */
 295                          devadd_null_flag = "0"b;           /* This is not NULLED, but null. */
 296                          devadd_add_type = "0000"b;         /* Internal null address representation */
 297                     end;
 298                else do;                                     /* real disk address */
 299                          devadd_add_type = add_type.disk;   /* Assume protected. */
 300                          records = records + 1;
 301                     end;
 302                ptp -> ptwa_bits (i) = devadd | null_devadd_not_in_core;
 303                                                             /* save final result in ptw */
 304           end;
 305 
 306 
 307           do i = last_page + 1 to sstp -> sst.pts (fixed (astep -> aste.ptsi, 2)) - 1;
 308                                                             /* Fill up rest of page table with nulls */
 309                ptp -> ptwa_bits (i) = null_devadd_not_in_core;
 310                ptp -> mptwa (i).devadd = fill_page_table_null_addr;
 311           end;
 312           aste.records = bit (fixed (records, 9), 9);
 313           if pc_trace
 314           then do;
 315                     call trace ("fill_page_table^-astep = ^p", astep);
 316                     if last_page <= 4
 317                     then call trace (half_line_of_words, ptp -> fword (0), ptp -> fword (1), ptp -> fword (2),
 318                               ptp -> fword (3));
 319                     else do;
 320                               do i = 0 to last_page by 8;
 321                                    call trace (line_of_words, ptp -> fword (i), ptp -> fword (i + 1),
 322                                         ptp -> fword (i + 2), ptp -> fword (i + 3), ptp -> fword (i + 4),
 323                                         ptp -> fword (i + 5), ptp -> fword (i + 6), ptp -> fword (i + 7));
 324                               end;
 325                          end;
 326                end;
 327           return;
 328 %page;
 329 truncate:
 330      entry (Astep, First_Page);                             /* entry to truncate a page table */
 331 
 332 
 333           tr_count_sw = "0"b;
 334           go to truncate_join;
 335 
 336 truncate_count:
 337      entry (Astep, First_Page, N_In_Core);
 338 
 339 
 340           tr_count_sw = "1"b;
 341 
 342 truncate_join:
 343           sstp = addr (sst_seg$);                           /* get a pointer to the sst */
 344 
 345           astep = Astep;                                    /* copy args into wired down stack */
 346           ptp = addrel (astep, sstp -> sst.astsize);
 347           cmp = sstp -> sst.cmp;                            /* and core map pointer */
 348           first_page = First_Page;
 349           last_page = sstp -> sst.pts (fixed (astep -> aste.ptsi, 3)) - 1;
 350                                                             /* get pt end for last page */
 351 
 352           records = 0;
 353           if pc_trace
 354           then call trace ("truncate^-^-astep = ^p", astep);
 355 
 356 /* the segment has an AST entry -- must clean up page tables and core map */
 357 
 358           call pmut$lock_ptl (oldmask, ptwp);               /* lock and mask */
 359 
 360           if pc_trace
 361           then do;
 362                     if last_page <= 4
 363                     then call trace (half_line_of_words, ptp -> fword (0), ptp -> fword (1), ptp -> fword (2),
 364                               ptp -> fword (3));
 365                     else do;
 366                               do i = 0 to last_page by 8;
 367                                    call trace (line_of_words, ptp -> fword (i), ptp -> fword (i + 1),
 368                                         ptp -> fword (i + 2), ptp -> fword (i + 3), ptp -> fword (i + 4),
 369                                         ptp -> fword (i + 5), ptp -> fword (i + 6), ptp -> fword (i + 7));
 370                               end;
 371                          end;
 372                end;
 373           n_in_core = 0;
 374 retry:
 375           ind = 0;
 376 
 377           do i = first_page to last_page;                   /* loop through all pages going */
 378                if ptp -> ptwa (i).os
 379                then do;                                     /* if out of service, must wait for io */
 380                          ind = fixed (rel (addr (ptp -> ptwa (i))), 18);
 381                                                             /* get event to wait on */
 382                          call wait_then_go_to (retry);      /* must go back to top after waiting */
 383                     end;
 384                count = "0"b;                                /* Assume no truncation */
 385 
 386 /* At this point, page is not o/s. If in core, devadd has core address. */
 387 
 388                from_core = atptwa (i).core;                 /* Remember in_coreness */
 389                devadd = ptp -> mptwa (i).devadd;            /* pick up the device address */
 390 
 391 /* At this point, devadd has disk or null address, unless in core */
 392 
 393                if from_core
 394                then do;                                     /* Page is in core */
 395                          n_in_core = n_in_core + 1;
 396                          cmep = addr (cmp -> cma (ptp -> core_ptwa (i).frame));
 397                                                             /* Get pointer to cme */
 398                          devadd = cmep -> cme.devadd;       /* and get the devadd for cleanup */
 399                          if ptp -> ptwa (i).wired
 400                          then sstp -> sst.wired = sstp -> sst.wired - 1;
 401                          call page$pcleanup (astep, i);     /* Fix up data bases, count quota, csl */
 402                          count = "0"b;                      /* page$cleanup did all work */
 403                     end;
 404 
 405 
 406 /* At this point, page is not in core. devadd has disk, null, or nulled */
 407 
 408                if devadd_bits.disk
 409                then if ^devadd_null_flag                    /* if nulling ... */
 410                     then do;
 411                               devadd_null_flag = "1"b;      /* Null the address */
 412                               count = "1"b;
 413                          end;
 414 
 415                ptp -> mptwa (i).devadd = devadd;            /* Insert right devadd in ptw */
 416                if count
 417                then records = records + 1;
 418 
 419           end;
 420           call loop_up_fms;
 421           if records ^= 0
 422           then do;
 423                     astep -> aste.fmchanged = "1"b;         /* Make sure we get an update_vtoce */
 424                     if ^astep -> aste.nqsw
 425                     then if astep -> aste.dirsw
 426                          then call quotaw$cu_for_pc (astep, -records, "1"b);
 427                          else if astep -> aste.par_astep
 428                          then call quotaw$cu_for_pc (ptr (astep, astep -> aste.par_astep), -records, "0"b);
 429                     astep -> aste.records = bit (fixed (fixed (astep -> aste.records, 9) - records, 9), 9);
 430                end;
 431 
 432 /* Now update the current segment length */
 433 
 434           do i = min (first_page - 1, last_page) to 0 by -1;/* min traps truncate to addr > aste size */
 435                devadd = ptp -> mptwa (i).devadd;
 436                if ptp -> atptwa (i).core
 437                then goto update_csl;
 438                if devadd_add_type & add_type.non_null
 439                then if ^devadd_null_flag
 440                     then go to update_csl;
 441           end;
 442 update_csl:
 443           astep -> aste.csl = bit (fixed (i + 1, 9), 9);
 444 
 445           if first_page = 0
 446           then do;
 447                     astep -> aste.damaged = "0"b;           /* empty is undamaged */
 448                     astep -> aste.fm_damaged = "0"b;
 449                end;
 450 
 451           call page$cam;                                    /* make sure our work takes */
 452           call pmut$unlock_ptl (oldmask, ptwp);             /* unlock and unmask */
 453           if tr_count_sw
 454           then N_In_Core = n_in_core;                       /* return for meter for callers that want. */
 455           return;
 456 %page;
 457 dumper_get_file_map:
 458      entry (Astep, Copy_Astep, File_Mapp, Deposit_Count, Listp, Pageno_Listp);
 459                                                             /* dumper entry for VTOCE update */
 460 
 461           dumper = "1"b;
 462           goto get_file_map_common;
 463 
 464 get_file_map:
 465      entry (Astep, Copy_Astep, File_Mapp, Deposit_Count, Listp, Pageno_Listp);
 466                                                             /* entry for VTOC update */
 467 
 468 
 469           dumper = "0"b;
 470 get_file_map_common:
 471           astep = Astep;                                    /* Copy astep */
 472           add_to_dmpr_map = "0"b;
 473           sstp = addr (sst_seg$);                           /* get SST base ptr */
 474           fmp = File_Mapp;
 475           cmp = sstp -> sst.cmp;                            /* get core map ptr */
 476           last_page = sstp -> sst.pts (fixed (astep -> aste.ptsi, 2)) - 1;
 477           no_deposit_no_return = (Listp = null) | aste.ddnp;
 478           getfmap_csl, getfmap_np, getfmap_nrec = 0;        /* Init counters */
 479           offed_sw = "0"b;                                  /* Don't need cam */
 480           return_pageno = (Pageno_Listp ^= null ());
 481 
 482           call pmut$lock_ptl (oldmask, ptwp);               /* Lock the pagetable lock */
 483 
 484           sstp = addr (sst_seg$);
 485           j = 0;                                            /* Init deposit index */
 486           do i = 0 to last_page;                            /* Walk the table */
 487                ptp = addrel (astep, sstp -> sst.astsize + i);
 488                                                             /* Get one page tbl ptr */
 489                devadd = ptp -> mptw.devadd;                 /* Get address from ptw */
 490                if devadd_bits.disk
 491                then do;                                     /* Disk addr, could be nulled */
 492                          if devadd_null_flag & ^no_deposit_no_return
 493                          then do;                           /* put in deposit list */
 494                                    devadd_null_flag = "0"b; /* zero the special internal flag */
 495                                    deposit_list (j) = devadd;
 496                                                             /* set to give to outside world */
 497                                    if return_pageno
 498                                    then pageno_list (j) = i;
 499 
 500                                    j = j + 1;               /* one more depositable address processed */
 501                                    devadd = get_file_map_vt_null_addr;
 502                                    ptp -> mptw.devadd = devadd;
 503                                                             /* coded null to file map and page table */
 504                               end;
 505                          else if devadd_null_flag & dumper
 506                          then devadd = get_file_map_vt_null_addr;
 507                     end;
 508                if devadd_bits.core
 509                then do;                                     /* A core address- move on up storage levels */
 510                          if ptw.phm
 511                          then do;                           /* Must off phm */
 512                                    ptw.phm1 = "1"b;         /* Mark mod status */
 513                                    ptw.phm = "0"b;          /* OFF PHM */
 514                                    offed_sw = "1"b;
 515                               end;
 516                          cmep = addr (cmp -> cma (core_ptw.frame));
 517                          devadd = cmep -> cme.devadd;       /* Reconsider this devadd */
 518                          if devadd_null_flag & ^ptw.phm1 & ^(ptw.os & cme.io)
 519                          then devadd = get_file_map_vt_null_addr;
 520                                                             /* This avoids damage to pure nulls incore */
 521                     end;
 522                if devadd_null_flag
 523                then if dumper
 524                     then devadd = get_file_map_dumper_non_null_addr;
 525                     else do;
 526                               devadd = get_file_map_vt_null_addr;
 527                               devadd_null_flag = "1"b;
 528                          end;                               /* if page is not on disk yet, or trunced,
 529                                                                we cannot fault in this page should we crash */
 530                else devadd_null_flag = (devadd_add_type = "0000"b);
 531                                                             /* Set outside-world null representation */
 532 
 533                if ^devadd_null_flag
 534                then do;                                     /* Real page */
 535                          getfmap_nrec = getfmap_nrec + 1;
 536                          getfmap_csl = i + 1;
 537                          if atptw.core
 538                          then getfmap_np = getfmap_np + 1;
 539                     end;
 540 
 541                rfm (i) = devadd;                            /* Send out agreed-upon devadd */
 542           end;
 543           curtime = clock ();                               /* loop_up_fms MAY do this, but we must be sure */
 544           if offed_sw
 545           then do;
 546                     call loop_up_fms;                       /* Pages were noted as modified. */
 547                     call page$cam;                          /* We turned off phm bits. */
 548                end;
 549 
 550           if aste.fms
 551           then add_to_dmpr_map = "1"b;
 552           if ^aste.gtus
 553           then if aste.np | aste.infp
 554                then /* have pages in, or subordinate astes */
 555                     aste.dtu = bit (fixed (curtime, 52), 52);
 556                                                             /* call it -in use- */
 557           copy_aste = astep -> aste;                        /* Copy ASTE structure */
 558 
 559 /* Update perishable items consistently to caller */
 560 
 561           astep -> aste.fms = "0"b;                         /* copy_aste has old value - this
 562                                                                assignment constitutes segment control's
 563                                                                recognition of modification */
 564           if ^dumper
 565           then do;
 566                     astep -> aste.fmchanged1 = astep -> aste.fmchanged;
 567                                                             /* Dont' lose fmchanged until updatev
 568                                                                turns this off, but ... */
 569                     astep -> aste.fmchanged = "0"b;         /* turn off p_c maintained bit. */
 570                end;
 571           call pmut$unlock_ptl (oldmask, ptwp);             /* And unlock the pagetables */
 572                                                             /* Use following items to avoid damaging */
 573                                                             /* segments with incore nonmod nulls. */
 574                                                             /* Copy out data to caller */
 575 
 576           copy_aste.np = bit (fixed (getfmap_np, 9), 9);
 577           copy_aste.records = bit (fixed (getfmap_nrec, 9), 9);
 578           copy_aste.csl = bit (fixed (getfmap_csl, 9), 9);
 579 
 580           unspec (Copy_Astep -> aste) = unspec (copy_aste); /* Copy the s  into our callers copy */
 581 
 582           do i = 0 to last_page;
 583                fmp -> file_map.fm (i) = rfm (i);            /* Upper bits into file map */
 584           end;
 585 
 586           do i = 0 to j - 1;                                /* copy out depositable addresses */
 587                Address_Array (i) = deposit_list (i);
 588                if return_pageno
 589                then Pageno_List (i) = pageno_list (i);
 590           end;
 591           Deposit_Count = j;                                /* deposit count */
 592           if add_to_dmpr_map & ^aste.nid & ^aste.per_process & ^aste.hc_sdw
 593           then call dbm_man$set_incr (fixed (aste.pvtx, 17), fixed (aste.vtocx, 17), (0));
 594 
 595           if pc_trace
 596           then do;
 597                     call trace ("get_file_map^-astep = ^p, fmp = ^p", astep, fmp);
 598                     if last_page <= 4
 599                     then call trace (half_line_of_words, ptp -> fword (0), ptp -> fword (1), ptp -> fword (2),
 600                               ptp -> fword (3));
 601                     else do;
 602                               do i = 0 to last_page by 8;
 603                                    call trace (line_of_words, ptp -> fword (i), ptp -> fword (i + 1),
 604                                         ptp -> fword (i + 2), ptp -> fword (i + 3), ptp -> fword (i + 4),
 605                                         ptp -> fword (i + 5), ptp -> fword (i + 6), ptp -> fword (i + 7));
 606                               end;
 607                          end;
 608                end;
 609           return;
 610 %page;
 611 updates:
 612      entry (Astep);                                         /* Entry to set file modified switches. */
 613 
 614           astep = Astep;                                    /* Copy arg to avoid page fault. */
 615           sstp = addr (sst_seg$);
 616           call pmut$lock_ptl (oldmask, ptwp);               /* lock and mask */
 617           call loop_up_fms;
 618           go to quit;
 619 
 620 update_incore_fms:
 621      entry (Astep);                                         /* used to get fms as accurate as possible */
 622 
 623 
 624           astep = Astep;
 625           sstp = addr (sst_seg$);
 626           ptp = addrel (astep, sst.astsize);
 627 
 628           if aste.np = "000"b3
 629           then return;
 630           offed_sw = "0"b;
 631 
 632 
 633           do i = 0 to fixed (aste.csl, 9) - 1;
 634                if ptwa (i).phm
 635                then do;
 636                          offed_sw = "1"b;                   /* remeber to cam */
 637                          ptwa (i).phm1 = "1"b;              /* Needed for real write */
 638                          ptwa (i).phm = "0"b;               /* This statement order is critical */
 639                     end;
 640           end;
 641 
 642           if offed_sw
 643           then do;
 644                     call loop_up_fms;
 645                     call page$cam;
 646                end;
 647 
 648           return;
 649 
 650 loop_up_fms:
 651      proc;                                                  /* Set fms up tree for hierarchy dumper. */
 652 
 653           dcl     astep1                 pointer;
 654 
 655           if aste.gtms
 656           then return;
 657           curtime = clock ();
 658           astep1 = astep;
 659           do while (rel (astep1));
 660                astep1 -> aste.fms = "1"b;
 661                astep1 -> aste.dtm = bit (fixed (curtime, 52), 52);
 662                astep1 = ptr (astep1, astep1 -> aste.par_astep);
 663           end;
 664 
 665      end loop_up_fms;
 666 
 667 /* You do not have to lock the page table or clear the AM for any of this. Phm1 will
 668    always be taken as a signal to write, and page$pwrite will turn them both off when
 669    camming. Once phm1 is on, failure to set phm, for not camming, is invisible. However, we
 670    do cam at the end so that the next call to this will get phms. */
 671 %page;
 672 flush:
 673      entry;                                                 /* here to write out all of core */
 674 
 675 /* Synchronized pages are handled as follows:
 676 
 677    flush_core - Page Control (page$pwrite) does the right thing, based on
 678    the time stamp in the page.
 679 
 680    flush - Modified synchronized pages are abandoned. This is safe, due to
 681    Ring-2 Data Management protocols.
 682 
 683 */
 684 
 685           dcl     flushing_for_pleasure  bit (1);
 686           dcl     hedonism               fixed bin;
 687           dcl     pleasure_flush_count   fixed bin;
 688 
 689           flushing_for_pleasure = "0"b;
 690           go to flush_join;
 691 
 692 flush_core:
 693      entry;                                                 /* here to start writes for all core. */
 694 
 695           flushing_for_pleasure = "1"b;
 696 
 697 flush_join:
 698           sstp = addr (sst_seg$);                           /* get pointers, and lock */
 699           pvt_arrayp = addr (pvt$array);
 700           cmp = sstp -> sst.cmp;
 701           if flushing_for_pleasure
 702           then hedonism = divide (sst.write_limit, 2, 17, 0);
 703           pleasure_flush_count = 0;
 704           call pmut$lock_ptl (oldmask, ptwp);               /* lock and mask */
 705 start_flush:
 706           do i = sst.first_core_block to sst.last_core_block;
 707                                                             /* index thru all cmes */
 708                ind = -1;                                    /* no wait event */
 709                cmep = addr (cmp -> cma (i));
 710 
 711                if (cme.ptwp ^= "000000"b3)
 712                then do;                                     /* has real page */
 713                          ptp = ptr (sstp, cme.ptwp);        /* get ptp */
 714                          astep = ptr (sstp, cme.astep);     /* get astep */
 715                          if ^aste.hc_part
 716                          then do;                           /* Don't bother with HC part segs */
 717                                    if ptw.os
 718                                    then ind = fixed (rel (ptp), 18);
 719                                                             /* if event, wait on it */
 720                                    else do;
 721                                              pageno =
 722                                                   fixed (rel (ptp), 18) - fixed (rel (astep), 18) - sstp -> sst.astsize;
 723                                              devadd = cme.devadd;
 724                                              if ptw.phm | ptw.phm1
 725                                              then /* Needs writing */
 726                                                   if drive_ok ((aste.pvtx))
 727                                                   then /* dont io bad disk */
 728                                                        if flushing_for_pleasure
 729                                                        then if cme.phm_hedge
 730                                                             then do;
 731                                                                       call page$pwrite (astep, pageno);
 732                                                                       sst.hedge_writes = sst.hedge_writes + 1;
 733                                                                       pleasure_flush_count = pleasure_flush_count + 1;
 734                                                                  end;
 735                                                             else cme.phm_hedge = ^aste.per_process;
 736                                                             /* change when we prevail across crashes */
 737                                                             /* if significant, write next time, if not written */
 738                                                        else do;
 739                                                             /* shutdown */
 740                                                                  if aste.synchronized
 741                                                                  then ptw.phm, ptw.phm1 = "0"b;
 742                                                             /* Abandon modified synch pages */
 743                                                                  else call page$pwrite (astep, pageno);
 744                                                             end;
 745                                              if ^flushing_for_pleasure
 746                                                             /* shutdown */
 747                                              then if ^(ptw.phm | ptw.phm1 | ptw.os)
 748                                                             /* Unmodified */
 749                                                   then if devadd_null_flag
 750                                                             /* Null address */
 751                                                        then call page$pcleanup (astep, pageno);
 752                                                             /* Reflect quota */
 753                                              if ptp -> ptw.os
 754                                              then /* if still being written, wait for it */
 755                                                   ind = fixed (cmp -> cma (i).ptwp, 18);
 756                                              if sstp -> sst.wtct > sstp -> sst.write_limit
 757                                              then /* if too many queued then */
 758                                                   if (ind > 0) & ^flushing_for_pleasure
 759                                                   then call wait_then_go_to (start_flush);
 760                                                             /* wait for one */
 761                                              if pleasure_flush_count >= hedonism
 762                                              then do;       /* All done with PTW */
 763                                                        pleasure_flush_count = 0;
 764                                                             /* time for a nap */
 765                                                        call pmut$unlock_ptl (oldmask, ptwp);
 766                                                        if flushing_for_pleasure
 767                                                        then call pxss$relinquish_priority;
 768                                                        call pmut$lock_ptl (oldmask, ptwp);
 769                                                   end;
 770                                         end;
 771                               end;
 772                     end;
 773           end;                                              /* end of cme array loop */
 774 
 775           if (ind > 0) & ^flushing_for_pleasure
 776           then call wait_then_go_to (start_flush);          /* Wait if shutdown and there is stuff to wait for */
 777           go to quit;                                       /* done */
 778 %page;
 779 list_deposited_add:
 780      entry (Astep, First_Page, Last_Page, Records, Listp, Pageno_Listp);
 781                                                             /* output deposits to seg ctl */
 782 
 783 
 784           astep = Astep;                                    /* copy params */
 785           first_page = First_Page;                          /* place to start */
 786           last_page = Last_Page;                            /* place to stop */
 787           return_pageno = (Pageno_Listp ^= null ());
 788           sstp = addr (sst_seg$);                           /* set up sstp */
 789           ptp = addrel (astep, sstp -> sst.astsize);
 790 
 791           records = 0;                                      /* init count of depositable records */
 792 
 793           call pmut$lock_ptl (oldmask, ptwp);               /* lock the PTL for real work */
 794 
 795           if last_page < 0                                  /* Scan whole page table */
 796           then last_page = sst.pts (fixed (astep -> aste.ptsi, 2)) - 1;
 797 
 798           do i = first_page to last_page;                   /* loop thru all ptws in ptl */
 799 
 800                devadd = ptp -> mptwa (i).devadd;            /* assume devadd in ptw -- */
 801 
 802 /* Any page in core or on the PD which has a nulled address
 803    has a right to it: hence, we only list those in the PTW */
 804 
 805                if devadd_bits.disk
 806                then if devadd_null_flag
 807                     then do;                                /* a real deposited address */
 808                               deposit_list (records) = devadd;
 809                                                             /* move to output array */
 810                               if return_pageno
 811                               then pageno_list (records) = i;
 812                               records = records + 1;        /* bump counter */
 813                               ptp -> mptwa (i).devadd, devadd = list_deposit_null_addr;
 814                          end;
 815           end;
 816 
 817           call pmut$unlock_ptl (oldmask, ptwp);             /* unlock the page tables */
 818           do i = 0 to records - 1;
 819                Address_Array (i) = deposit_list (i);        /* return to argument array */
 820                if return_pageno
 821                then Pageno_List (i) = pageno_list (i);
 822           end;
 823 
 824           Records = records;                                /* return the count */
 825           return;
 826 %page;
 827 deposit_list:
 828      entry (Pvtx, Records, Listp, Vtocx, Pageno_Listp);     /* entry to deposit a list of addresses */
 829 
 830 
 831           records = Records;                                /* number of records to be deposited */
 832           pvtx = Pvtx;                                      /* phys volume index */
 833 
 834 /* The paged fsdct strategy states that the page table lock need
 835    not be locked to deposit. Nobody can withdraw our bit unless we
 836    have a problem, and if we find an unprotected address at
 837    the time we deposit, this will be the case irrespective
 838    of the page table lock. */
 839 
 840           do i = 0 to records - 1;
 841                Devadd_Array (i).add_type = add_type.disk;   /* Make up for sins of vtoc_man */
 842           end;
 843 
 844           call page$deposit_list ((pvtx), Listp, 1, records, Vtocx, Pageno_Listp);
 845 
 846           return;
 847 
 848 
 849 /*  Auxiliary entry for truncation/deposition of vtoceless segs */
 850 
 851 truncate_deposit_all:
 852      entry (Astep);
 853 
 854 
 855           astep = Astep;                                    /* Copy astep */
 856 
 857           if aste.uid
 858           then call syserr (1, "pc: truncate_deposit_all call on VTOCed seg at ^p", astep);
 859           call truncate (astep, 0);                         /* Clean up w.r.t. pc */
 860 
 861           if aste.hc_sdw
 862           then return;                                      /* Don't attempt semi-hc deposit */
 863 
 864           call list_deposited_add (astep, 0, -1, records, addr (deposit_list), null ());
 865 
 866           call page$deposit_list ((aste.pvtx), addr (deposit_list), 1, records, -1, null ());
 867 
 868           return;
 869 %page;
 870 move_page_table:
 871      entry (Old_Astep, New_Astep);
 872 
 873 
 874           sstp = addr (sst_seg$);
 875           cmp = sstp -> sst.cmp;
 876           old_astep = Old_Astep;
 877           new_astep = New_Astep;
 878           call pmut$lock_ptl (oldmask, ptwp);               /* lock and mask */
 879 
 880           if pc_trace
 881           then call trace ("move_page_table^-old astep = ^p, new astep = ^p", old_astep, new_astep);
 882 
 883           old_ptp = addrel (old_astep, sstp -> sst.astsize);/* get pointer to old page table */
 884           new_ptp = addrel (new_astep, sstp -> sst.astsize);/* get pointer to new page table */
 885           do i = 0 to sstp -> sst.pts (fixed (old_astep -> aste.ptsi, 3)) - 1;
 886                new_ptp -> ptwa_bits (i) = old_ptp -> ptwa_bits (i);
 887                                                             /* copy page table words */
 888 
 889                old_ptp -> ptwa_bits (i) = null_devadd_not_in_core;
 890                old_ptp -> mptwa (i).devadd = pc_move_page_table_1_null_addr;
 891                ptp = addr (new_ptp -> ptwa (i));            /* point to specific ptw */
 892                if atptw.core
 893                then do;                                     /* ptw describes core */
 894                          cmep = addr (cmp -> cma (core_ptw.frame));
 895                                                             /* address CME */
 896                          cme.ptwp = rel (ptp);              /* associate CME with new PTW */
 897                          cme.astep = rel (new_astep);       /* ditto ASTE */
 898                          devadd = cme.devadd;               /* get devadd from cme if in core */
 899                          if cme.notify_requested            /* if someone was waiting on old PTW event, then notify .. */
 900                          then call pxss$notify (fixed (rel (addr (old_ptp -> ptwa (i))), 18));
 901                                                             /* him, causing him to rewait on new event */
 902                     end;
 903                else devadd = mptw.devadd;                   /* get devadd out of ptw if not in core */
 904           end;
 905 
 906           do i = sstp -> sst.pts (fixed (old_astep -> aste.ptsi, 3))
 907                to sstp -> sst.pts (fixed (new_astep -> aste.ptsi, 3)) - 1;
 908 
 909                new_ptp -> ptwa_bits (i) = null_devadd_not_in_core;
 910                new_ptp -> mptwa (i).devadd = pc_move_page_table_2_null_addr;
 911           end;
 912 
 913 /* Now copy the old ASTE into the new ASTE, except fp, bp, ptsi and marker */
 914 
 915           new_astep -> aste_part.two = old_astep -> aste_part.two;
 916 
 917           go to quit;
 918 %page;
 919 
 920 
 921 segmove:
 922      entry (Move_Astep, Old_Astep, New_Astep, New_Pvtx, New_Vtocx, Records, Listp, Pageno_Listp, Code);
 923 
 924           astep = Move_Astep;                               /* aste under segmove */
 925           old_astep = Old_Astep;                            /* put old addresses here for pcrsst */
 926           new_astep = New_Astep;                            /* put new addresses here for pcrsst or caller to deposit */
 927           new_pvtx = New_Pvtx;                              /* we can reference them without the */
 928           new_vtocx = New_Vtocx;                            /* AST lock */
 929           sstp = addr (sst_seg$);
 930           cmp = sst.cmp;
 931           new_ptp = addwordno (new_astep, sst.astsize);     /* use that page table
 932                                                                to store up addresses on new volume */
 933           old_ptp = addwordno (old_astep, sst.astsize);     /* use that page table
 934                                                                to remember old addesses for the purposes of pcrsst */
 935           move_ptp = addwordno (astep, sst.astsize);        /* this is the page table of affliction. */
 936 
 937           if astep -> aste.ptsi ^= new_astep -> aste.ptsi | new_astep -> aste.ptsi ^= old_astep -> aste.ptsi
 938           then do;
 939                     Code = error_table_$bad_arg;
 940                     return;
 941                end;
 942 
 943           last_page = sst.pts (fixed (astep -> aste.ptsi, 2)) - 1;
 944 
 945           call lock$lock_fast (addr (sst.segmove_lock));    /* Only one at a time */
 946           sst.segmove_new_addr_astep = new_astep;           /* pc_check_tables_ should deposit anything in here
 947                                                                or at least bang on the pvte inconsistency count. */
 948 
 949           call pmut$lock_ptl (oldmask, ptwp);               /* will be unlocked if we have to wait */
 950 
 951 /**** Note that deposit_list is declared 0:255 and page$deposit_list expects a
 952       1:256 array. withdraw_list expects 0:255. Shouldn't be any trouble */
 953 
 954           segmove_records_in_hand = 0;
 955           segmove_total_records,                            /* This many is the grand total that we have accumulated */
 956                segmove_records_needed                       /** This many are the number that we need to add to the record pile */
 957                = fixed (astep -> aste.records, 9);          /* This is the first guess as to the total number of records needed */
 958                                                             /* However, the guess may be too low since the PTL is unlocked. So */
 959                                                             /* even when we get records_in_hand up and records_needed to 0, we may */
 960                                                             /* have to add to total_records and reset records_needed to get the rest */
 961 
 962 
 963           move_tries = 0;
 964 
 965 augment_record_pile:
 966 /**** + Debug
 967       call syserr (ANNOUNCE, "pc: (at ARP) aste: np = ^d, records = ^d, csl = ^d", fixed (aste.np), fixed (aste.records), fixed (aste.csl));
 968 */
 969           code = 0;
 970           do while (segmove_records_needed > 0 & code = 0); /* keep calling until free_store gives all we want */
 971                call page$withdraw_list (new_pvtx, new_ptp, segmove_records_in_hand, segmove_records_needed, ind, code);
 972                                                             /* since parm(3) is zero based, zero records_in_hand is interpreted */
 973                                                             /* as "put the next record in slot zero" which deposit addresses as  */
 974                                                             /* slot one. */
 975 
 976                if ind ^= 0
 977                then /* wait for volmap */
 978                     call wait_then_go_to (augment_record_pile);
 979           end;
 980           if code ^= 0
 981           then do;                                          /* out-of-volume */
 982                     Code = code;
 983                     go to SEGMOVE_ABORT_RETURN;
 984                end;
 985 
 986 /**** At this point, we own all the records we need. We can release the
 987       PTL while we drag the segment into memory. */
 988 
 989 /****  NOTE -- at this point new_ptp contains segmove_total_records records.
 990       segmove_records_needed can be re-used.
 991       if we find that we need more records, total_records will grow,
 992       but in_hand will continue to be the number of addresses in new_addr_aste. */
 993 
 994 move_retry:
 995           segmove_records_needed = 0;                       /* re-count the number we need under the PTL */
 996 
 997 /**** + Debug
 998       call syserr (ANNOUNCE, "pc: (at MRT) aste: np = ^d, records = ^d, csl = ^d", fixed (aste.np), fixed (aste.records), fixed (aste.csl));
 999 */
1000 
1001           move_tries = move_tries + 1;
1002           if move_tries > 1000
1003           then go to SEGMOVE_ABORT_RETURN;
1004 
1005           n_io_started = 0;
1006 SEGMOVE_EXAMINE_PAGES:
1007           do i = 0 to last_page;                            /* get all pages into memory */
1008 RE_EXAMINE_PAGE:
1009                if move_ptp -> ptwa (i).os
1010                then do;                                     /* wait for i and  also o (quiesce) */
1011 
1012                          ind = wordno (addr (move_ptp -> ptwa (i)));
1013                                                             /* event to wait on */
1014                          n_io_started = n_io_started + 1;
1015                          if n_io_started > sst.segmove_io_limit
1016                          then call wait_then_go_to (move_retry);
1017                     end;
1018                else if move_ptp -> atptwa (i).disk
1019                then do;
1020                          sst.segmove_n_reads = sst.segmove_n_reads + 1;
1021                          call page$pread (astep, i, temp_ind);
1022                                                             /* put event into temporary... */
1023                          if temp_ind ^= 0
1024                          then do;
1025                                    ind = temp_ind;          /* OK to mung it now... */
1026                                    n_io_started = n_io_started + 1;
1027                                    if n_io_started > sst.segmove_io_limit
1028                                    then call wait_then_go_to (move_retry);
1029                               end;
1030                          else go to RE_EXAMINE_PAGE;        /* ZERO! */
1031                     end;
1032                else if move_ptp -> atptwa (i).core
1033                then do;                                     /* in memory - keep it there */
1034                          segmove_records_needed = segmove_records_needed + 1;
1035                                                             /* got another real one in memory */
1036                          cmep = addr (cmp -> cma (move_ptp -> core_ptwa (i).frame));
1037                          cme.pin_counter = 1000;
1038                          if astep -> aste.synchronized & (move_ptp -> core_ptwa (i).phm | move_ptp -> core_ptwa (i).phm1)
1039                                                             /* any modified page of a synch segment is held until proven elsewise */
1040                          then call segmove_synch_page (astep, cmep, i);
1041                     end;
1042                else if move_ptp -> ptwa (i).add_type ^= "0000"b
1043                                                             /* mysterious non-null */
1044                then /* but unknown! */
1045                     call syserr (CRASH, "pc$segmove: unexpected address type ^4b", move_ptp -> ptwa (i).add_type);
1046           end SEGMOVE_EXAMINE_PAGES;
1047 
1048 /**** At arrival here, the PTL is locked (nothing can be evicted)
1049       and either all the pages are in memory, or we have some read-ahead
1050       activity. */
1051 
1052           if n_io_started > 0
1053           then call wait_then_go_to (move_retry);           /* ind is last read ahead page */
1054 
1055           sst.segmove_max_tries = max (move_tries, sst.segmove_max_tries);
1056 
1057 /**** No read aheads. all pages found in core, PTL is locked.
1058       Start final countdown. Unless, somehow, the segment grew ... */
1059 
1060           if segmove_records_needed > segmove_total_records
1061           then do;                                          /* When we counted under the PTL and made them stand still, we found more of them. */
1062                     segmove_total_records = segmove_records_needed;
1063                                                             /* new count is the right count */
1064                     segmove_records_needed = segmove_records_needed - segmove_records_in_hand;
1065                                                             /* count of additional records required */
1066                     go to augment_record_pile;              /* get 'em */
1067 
1068                end;
1069 
1070 /**** We have an adequate supply of records on the new volume,
1071       and everything is in memory. Here we go... */
1072 
1073 /**** Since the move segment page table is in its final state
1074       (all addresses null or in core) we can copy all the ptw's
1075       to the old_addr_aste. pcrsst will find them there and
1076       put them back. All the new addreses have been accumulated
1077       in the new_addr_aste, where shutdown can deposit them.
1078 
1079       Thus the rules are:  if new_addr_astep ^= null (), deposit
1080       all the non-null addresses in its page table. pc_check_tables_
1081       does not currently concern itself with deposits, so these
1082       addresses are abandoned.
1083 
1084       if the move_astep ^= null (), then copy the page table
1085       from the old_addr_aste to the move_aste. The old_addr_astep
1086       is guaranteed to be non-null.
1087 
1088       if the old_addr_astep ^= null(), then zap all its ptw's
1089       to be null addresses. */
1090 
1091           sst.segmove_old_addr_astep = old_astep;           /* still full of nulls */
1092                                                             /* now, pcrsst will zero all these ptw's */
1093 
1094           begin;                                            /* copy the page table wholesale from move to old astep */
1095                declare pt                     (0:last_page) bit (36) aligned based;
1096                old_ptp -> pt = move_ptp -> pt;
1097           end;                                              /* this can be copied back verbatim by pc_check_tables_
1098                                                                since we are under the PTL and nothing can change. */
1099 
1100           sst.segmove_pvtx = astep -> aste.pvtx;
1101           sst.segmove_vtocx = astep -> aste.vtocx;
1102           sst.segmove_astep = astep;                        /* now, pcrsst will copy all the devadds from old to here */
1103 
1104 /**** Now it only takes one loop to put the new disk devadds into
1105       the move aste. */
1106 
1107           segmove_records_used = 0;
1108 
1109           if segmove_total_records < fixed (aste.np)
1110           then call syserr (CRASH, "pc$segmove: miscounted pages.");
1111 
1112           do i = 0 to last_page;                            /* now swap addresses */
1113                devadd = move_ptp -> mptwa (i).devadd;       /* either core or null */
1114 /**** + Debug
1115       call syserr (ANNOUNCE, "sgm: page ^d ptw devadd ^.3b",
1116       i, devadd);
1117 */
1118                if (devadd_add_type & add_type.core) ^= ""b  /* core */
1119                then do;
1120                          if segmove_records_used > segmove_records_in_hand
1121                          then call syserr (CRASH, "pc$segmove: out of records during move");
1122                          cmep = addr (cmp -> cma (move_ptp -> core_ptwa (i).frame));
1123                          move_ptp -> core_ptwa (i).phm1 = "1"b;
1124                                                             /* modify! */
1125                                                             /* it will get hierarchy incrementalled, which is unfortunate */
1126                          segmove_deposit_list (segmove_records_used) = cme.devadd;
1127 /**** + Debug
1128       call syserr (ANNOUNCE, "sgm: old cme devadd ^.3b", cme.devadd);
1129 */
1130                          pageno_list (segmove_records_used) = i;
1131                          devadd = new_ptp -> mptwa (segmove_records_used).devadd;
1132                                                             /* new record address + disk flag */
1133 /**** + Debug
1134       call syserr (ANNOUNCE, "sgm: new devadd ^.3b", devadd);
1135 */
1136                          new_ptp -> mptwa (segmove_records_used).devadd = segmove_new_addr_null_addr;
1137                                                             /* order here is noncritical,
1138                                                                pc check tables will zonk all of these anyway */
1139                          devadd_null_flag = "1"b;           /* you're not on disk yet, buddy! */
1140                          cme.devadd = devadd;
1141                          cme.phm_hedge = "1"b;
1142 /**** + Debug
1143       call syserr (ANNOUNCE, "sgm: new devadd in CME ^.3b", devadd);
1144 */
1145                          cme.pin_counter = 0;               /* don't hold page any longer */
1146                          segmove_records_used = segmove_records_used + 1;
1147                     end;
1148           end;
1149 
1150           if sst.crash_test_segmove
1151           then call syserr (CRASH, "pc$segmove: crashing in segment mover.");
1152 
1153           astep -> aste.pvtx = new_pvtx;                    /* finish the swap */
1154           astep -> aste.vtocx = new_vtocx;                  /* ... */
1155           astep -> aste.fmchanged = "1"b;                   /* ... */
1156 
1157           sst.segmove_astep = null;                         /* dont fix addresses, pvtx, or vtocx.
1158                                                                and dont copy page table from old_addr_aste */
1159           sst.segmove_pvtx = 0;
1160           sst.segmove_vtocx = 0;
1161 
1162 /**** Now cleanup the old addresses, unbinding them from PTW's etc. */
1163 
1164           begin;
1165                declare pt                     (0:last_page) bit (36) based;
1166                declare px                     fixed bin;
1167 
1168                declare 1 nptw                 aligned like l68_ptw;
1169                declare ptwp                   pointer;
1170 
1171                unspec (nptw) = ""b;
1172                nptw.add = segmove_old_addr_null_addr;       /* thats whats left */
1173                do px = 0 to last_page;
1174                     ptwp = addr (old_ptp -> pt (px));       /* all are core addresses, we are under PTL after verifying that */
1175                     devadd = ptwp -> mptw.devadd;
1176                     if (devadd_add_type & add_type.non_null) ^= ""b
1177                     then do;
1178                               if (devadd_add_type & add_type.core) = ""b
1179                               then call syserr (CRASH, "pc$segmove: non-memory PTW in old_addr_aste.");
1180                               old_ptp -> pt (px) = unspec (nptw);
1181                          end;
1182                end;
1183           end;
1184           sst.segmove_old_addr_astep = null ();
1185 
1186           call pmut$unlock_ptl (oldmask, ptwp);
1187 
1188           if segmove_records_in_hand > segmove_records_used
1189           then /* some records on new pvt left over */
1190                call page$deposit_list (new_pvtx, new_ptp, segmove_records_used + 1,
1191                     segmove_records_in_hand - segmove_records_used, -1, null ());
1192 
1193           call lock$unlock_fast (addr (sst.segmove_lock));
1194 
1195           Address_Array = segmove_deposit_list;             /* out from under PTL */
1196           Pageno_List = pageno_list;                        /* so we can copy to unwired stack_0 */
1197           Records = segmove_records_used;                   /* starts at zero, used as index
1198                                                                to zero-based array, then bumped. */
1199 
1200           return;
1201 
1202 SEGMOVE_ABORT_RETURN:
1203           call pmut$unlock_ptl (oldmask, ptwp);
1204           if segmove_records_in_hand > 0
1205           then call page$deposit_list (new_pvtx, new_ptp, 1, segmove_records_in_hand, -1, null ());
1206                                                             /* Abandon all the records that we collected */
1207           if Code = 0
1208           then                                              /** we may have a specific code */
1209                Code = error_table_$action_not_performed;
1210           call lock$unlock_fast (addr (sst.segmove_lock));
1211           return;
1212 ^L
1213 
1214 segmove_synch_page:
1215      procedure (astep, cmep, pagex);
1216 
1217           declare (astep, cmep)          pointer;
1218           declare pagex                  fixed bin;
1219 
1220 
1221 
1222 /**** Call page control to write the page itself. If the synch_hold
1223       is legit, then .synch_hold will still be on when pwrite returns.
1224       If .synch_hold is off, the page is no longer held. */
1225 
1226           call page$pwrite (astep, pagex);
1227 
1228           if ^cmep -> cme.synch_held
1229           then do;
1230                     sst.segmove_synch_disappeared = sst.segmove_synch_disappeared + 1;
1231                     return;                                 /* page is fine, we can move it */
1232                end;
1233 
1234           Code = error_table_$synch_seg_segmove;
1235           go to SEGMOVE_ABORT_RETURN;
1236      end segmove_synch_page;
1237 
1238 
1239 %page;
1240 drive_ok:
1241      proc (pvtx) returns (bit (1) aligned);                 /* test drive state */
1242 
1243           dcl     pvtx                   fixed bin;
1244 
1245           return (^pvt_array (pvtx).device_inoperative);
1246 
1247      end drive_ok;
1248 %page;
1249 wait_then_go_to:
1250      procedure (lab);                                       /* quick internal proc to trace and wait for
1251                                                                page control events */
1252           dcl     lab                    label local;
1253 
1254           if ind = 0
1255           then call syserr (CRASH, "pc: waiting for zero event.");
1256 
1257           if pc_trace
1258           then call trace ("wait for i/o");
1259           call page$cam;                                    /* make sure any work done so far gets done */
1260           call page$pwait (ind);                            /* wait for event */
1261           go to lab;
1262 
1263      end wait_then_go_to;
1264 
1265 /* format: off */
1266 %page; %include sst;
1267 %page; %include pvte;
1268 %page; %include cmp;
1269 %page; %include aste;
1270 %page; %include fm;
1271 %page; %include null_addresses;
1272 %page; %include add_type;
1273 %page; %INCLUDE "ptw.macro";
1274 %page; %include syserr_constants;
1275 %page;
1276 /* BEGIN MESSAGE DOCUMENTATION
1277 
1278    Message:
1279    pc: unprotected address DDDDD in DSKX_NN VTOCX
1280 
1281    S:     $info
1282 
1283    T:     $run
1284 
1285    M:     The disk address DDDDD
1286    is not marked as protected
1287    in the record usage map for the volume mounted on DSKX_NN.
1288    This condition has been discovered
1289    while activating the segment with VTOC index VTOCX.
1290    The segment's damaged switch is turned on, and a page of zeros will
1291    replace the bad address. This condition may be symptomatic of disk
1292    or other hardware failure.
1293 
1294    A:     $inform
1295 
1296 
1297    Message:
1298    pc: truncate_deposit_all call on VTOCed seg at ASTEP
1299 
1300    S:     $crash
1301 
1302    T:     $run
1303 
1304    M:     A call to pc$truncate_deposit_all
1305    has been made on a segment for which this operation is not allowed.
1306    The AST entry at ASTEP should have a zero unique ID
1307    but it does not.
1308    $err
1309    $crashes
1310 
1311    A:     $recover
1312 
1313 
1314    END MESSAGE DOCUMENTATION */
1315 
1316      end pc;