1 " ***********************************************************
2 " * *
3 " * Copyright, C Honeywell Bull Inc., 1987 *
4 " * *
5 " * Copyright, C Honeywell Information Systems Inc., 1982 *
6 " * *
7 " ***********************************************************
8
9 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
10 "
11 " stock
12 "
13 " Record Stock Management Routines
14 "
15 " Entries:
16 "
17 " withdraw - withdraws a single record address from a stock
18 "
19 " withdraw_range - withdraws a single record address from
20 " a stock within a range of addresses
21 "
22 " withdraw_range_ext - same as withdraw_range, available
23 " outside ALM Page Control
24 "
25 " deposit - deposits a single record address into a stock
26 "
27 " reset_os - resets all out-of-service bits in a stock
28 "
29 " flush_os - removes all out-of-service entries from a stock.
30 " Called when there is an unrecoverable I/O error
31 " on a Volume Map page.
32 "
33 " check_low_threshold - checks for stock below threshold and
34 " selects a volume map page to replenish it
35 "
36 " recover - adjust stock counts called during ESD
37 "
38 " Written January 1982 by J. Bongiovanni
39 " Modified July 1982, J. Bongiovanni, for withdraw_range_ext
40 "
41 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
42
43 name stock
44 segdef deposit
45 segdef withdraw
46 segdef withdraw_range
47 segdef withdraw_range_ext
48 segdef reset_os
49 segdef flush_os
50 segdef check_low_threshold
51 segdef recover
52
53 bool live_address,377777
54 bool os_address,400000
55
56 reset_os_upper_bits:
57 oct 377777777777 " reset_os
58 oct 000000777777 " flush_os
59 reset_os_lower_bits:
60 oct 777777377777 " reset_os
61 oct 777777000000 " flush_os
62
63 high_record_address:
64 oct 377777000000
65
66 "^L
67 include aste
68 "^L
69 include page_info
70 "^L
71 include ptw
72 "^L
73 include pvte
74 "^L
75 include pxss_page_stack
76 "^L
77
78 include stack_frame
79 ^L
80 include stock_seg
81 "^L
82 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
83 "
84 " withdraw - routine to withdraw a single record address
85 "
86 " tsx7 stock$withdraw
87 " <return if no addresses in stock>
88 " <return if succeed with withdrawal>
89 "
90 " On entry
91 " ab -> stock_seg$meters
92 " bb -> stock of interest
93 "
94 " On exit
95 " Areg contains address
96 "
97 "
98 " withdraw_range - routine to withdraw a single record address
99 " within a range specified
100 "
101 " Same as above, except on entry
102 " AU = high address rec < high address
103 " AL = low address rec >= low address
104 "
105 " withdraw_range_ext - withdraw range accessible outside
106 " ALM Page control
107 "
108 " call page$withdraw_range pvtep low_address high_address record_address
109 "
110 " No locks are required by this routine.
111 "
112 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
113
114 withdraw_range_ext:
115 push
116
117 stz ap|8,* " Clear returned address
118 tsx6 page_fault$init_savex
119
120 eppbp ap|2,* " bp -> ptr -> PVTE
121 eppbp bp|0,* " bp -> PVTE
122 lprpbb bp|pvte.volmap_stock_ptr " bb -> stock
123 epbpab bb|0 " ab -> base of stock_seg
124 eppab ab|stock_seg.meters " ab -> meters
125
126 lda ap|6,* " AL = high address
127 als 18 " AU = high address
128 ora ap|4,* " AU = high address, AL = low address
129 tsx7 withdraw_range " Try for an address
130 tra withdraw_range_ext_ret " None
131
132 eppap sp|stack_frame.arg_ptr,* " Restore argument list ptr
133 sta ap|8,* " Record address
134
135 withdraw_range_ext_ret:
136 return
137
138
139
140 withdraw:
141 eax6 0 " withdraw
142 stz stock_temp_1 " low address
143 lda high_record_address
144 sta stock_temp_2 " high address
145 increment ab|rsmeters.n_withdraw_attempt
146 tra withdraw_join
147
148 withdraw_range:
149 eax6 1 " withdraw_range
150 increment ab|rsmeters.n_withdraw_range
151 sta stock_temp_2 " high address
152 ana -1,dl
153 als 18 " low address
154 sta stock_temp_1
155
156 withdraw_join:
157 lxl0 bb|record_stock.stock_offset
158 eppap bb|0,x0 " ap -> stock
159
160 eax6 0,x6 " withdraw_range?
161 tnz withdraw_set_begin " Yes
162
163 lxl0 bb|record_stock.search_index " Roving pointer
164 eax0 -1,x0
165 tra withdraw_common
166
167 withdraw_retry:
168 eax6 0,x6 " withdraw_range?
169 tze withdraw_set_begin " No
170 eax6 1,x6 " Bump bail-out counter
171 cmpx6 2,du " Gone through once
172 tpl 0,x7 " Yes -- once is enough
173
174 withdraw_set_begin:
175 ldx0 -1,du " Start at the beginning
176
177 withdraw_common:
178 ldx1 bb|record_stock.n_free_in_stock " Any free?
179 tze 0,x7 " No -- give up
180
181 withdraw_loop:
182 increment ab|rsmeters.withdraw_stock_steps " Meter
183 eax0 1,x0 " Next 2 entires
184 cmpx0 bb|record_stock.n_words_in_stock " Any left
185 tpl withdraw_retry " No - retry from the top
186
187 withdraw_loop_retry:
188 ldq ap|0,x0 " Next 2 entries
189 tze withdraw_loop " Both empty
190 lda ap|0,x0 " Protected by Q, stacq
191 eax1 0,au " Check upper address
192 tmoz withdraw_check_lower " Empty or out-of-service
193 cmpx1 stock_temp_1 " >= low address
194 tmi withdraw_check_lower " No
195 cmpx1 stock_temp_2 " < high address
196 tpl withdraw_check_lower " No
197 ana -1,dl " Mark upper as empty
198 tra withdraw_try " And attempt lockless withdraw
199 withdraw_check_lower:
200 eax1 0,ql " Look at lower entry
201 tmoz withdraw_loop " Empty or out-of-service
202 cmpx1 stock_temp_1 " >= low address
203 tmi withdraw_loop " No
204 cmpx1 stock_temp_2 " < high address
205 tpl withdraw_loop " No
206 ana -1,du " Mark lower as empty
207
208 withdraw_try:
209 stacq ap|0,x0 " Attempt lockless withdraw
210 tze withdraw_succeed " Made it
211 increment ab|rsmeters.withdraw_stock_losses
212 tra withdraw_loop_retry " Meter and retry
213
214 withdraw_succeed:
215 eax6 0,x6 " withdraw_range ?
216 tnz withdraw_leave_pointer " Yes -- don't adjust pointer
217 sxl0 bb|record_stock.search_index " Roving pointer
218 withdraw_leave_pointer:
219 ldq bb|record_stock.n_free_in_stock " Adjust count lockless
220 lda bb|record_stock.n_free_in_stock
221 sba 1,du " One fewer free record
222 stacq bb|record_stock.n_free_in_stock
223 tnz withdraw_leave_pointer " Lost race, retry
224
225 eaa 0,x1 " Record address
226 arl 18 " Areg = record address
227 increment ab|rsmeters.n_pages_withdraw_stock
228 tra 1,x7
229
230 "^L
231 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
232 "
233 " deposit - routine to deposit a single address
234 "
235 " tsx7 stock$deposit
236 " <return if fail>
237 " <return if succeed>
238 "
239 " On entry,
240 " Areg = address to deposit
241 " ab -> stock_seg$meters
242 " bb -> stock of interest
243 "
244 " No locks are required by this routine.
245 "
246 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
247
248 deposit:
249 cana live_address,dl " Valid record address
250 tze page_error$deposit_zero_address " No - bad lossage
251
252 sta stock_temp_1 " Record address
253 als 18 " Into upper
254 sta stock_temp_2
255
256 increment ab|rsmeters.n_deposit_attempt
257
258 lxl0 bb|record_stock.stock_offset
259 eppap bb|0,x0 " ap -> stock
260 lxl0 bb|record_stock.search_index " Roving pointer
261 eax0 1,x0 " Adjust for initial decrement
262 tra deposit_common
263
264 deposit_retry:
265 ldx0 bb|record_stock.n_words_in_stock " Start at the top
266
267 deposit_common:
268 lxl1 bb|record_stock.n_os_in_stock " Check whether any free slots
269 adlx1 bb|record_stock.n_free_in_stock " exist
270 cmpx1 bb|record_stock.n_in_stock
271 tpl 0,x7 " None free
272
273 deposit_loop:
274 increment ab|rsmeters.deposit_stock_steps
275 eax0 -1,x0 " 2 entries/word
276 tmi deposit_retry " None left
277
278 deposit_loop_retry:
279 ldq ap|0,x0 " Next 2 entries
280 lda ap|0,x0 " Protected by Qreg, stacq
281 tze deposit_try_upper " Both entries free
282
283 eax1 0,au " Check upper entry
284 tnz deposit_check_lower " Not free
285 deposit_try_upper:
286 ora stock_temp_2 " Dep address into upper
287 tra deposit_try
288
289 deposit_check_lower:
290 eax1 0,al " Check lower entry
291 tnz deposit_loop " Not empty
292 ora stock_temp_1 " Dep address into lower
293
294 deposit_try:
295 stacq ap|0,x0 " Lockless deposit
296 tze deposit_succeed " We win
297 increment ab|rsmeters.deposit_stock_losses
298 tra deposit_loop_retry " Lose - meter and retry
299
300 deposit_succeed:
301 lda 1,dl " Set up to increment number OS
302 ldx1 stock_temp_2 " Address just deposited
303 tmi deposit_os " An out-of-service address
304 lda 1,du " Set up to increment number free
305 sxl0 bb|record_stock.search_index " Roving pointer
306
307 deposit_os:
308 sta stock_temp_2 " Save for lost race
309 deposit_os_retry:
310 ldq bb|record_stock.n_free_in_stock
311 lda stock_temp_2 " Restore
312 adla bb|record_stock.n_free_in_stock
313 stacq bb|record_stock.n_free_in_stock " Lockless update
314 tnz deposit_os_retry " Lost - retry
315
316 increment ab|rsmeters.n_pages_deposit_stock
317 tra 1,x7
318
319 "^L
320 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
321 "
322 " reset_os - routine to reset all out-of-service bits
323 "
324 " tsx7 stock$reset_os
325 "
326 " On entry,
327 " ab -> stock_seg$meters
328 " bb -> stock of interest
329 "
330 " No locks are required by this routine
331 "
332 " flush_os - routine to remove all out-of-service entries
333 " from a stock.
334 "
335 " On entry, same as above
336 "
337 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
338
339 reset_os:
340 eax6 0 " reset_os
341 tra reset_os_common
342
343 flush_os:
344 eax6 1 " flush_os
345
346 reset_os_common:
347 increment ab|rsmeters.reset_os_calls
348
349 lxl0 bb|record_stock.stock_offset
350 eppap bb|0,x0 " ap -> stock
351 ldx0 bb|record_stock.n_words_in_stock
352
353 reset_os_loop:
354 eax0 -1,x0 " One less
355 tmi 0,x7 " Done - exit
356
357 reset_os_loop_retry:
358 ldq ap|0,x0 " Next 2 addresses
359 ldx1 0,du " Count of OS reset
360 lda ap|0,x0 " Protected by Qreg, stacq
361 tze reset_os_loop " None in use
362 tpl reset_os_check_lower " High address not OS
363 ldx1 1,du " Count of OS reset
364 ana reset_os_upper_bits,x6 " Reset/Flush
365 reset_os_check_lower:
366 cana =o400000,dl " Low address OS
367 tze reset_os_try " No
368 adlx1 1,du " Bump counter
369 ana reset_os_lower_bits,x6 " Reset/Flush
370
371 reset_os_try:
372 eax1 0,x1 " Any to reset
373 tze reset_os_loop " No
374 stacq ap|0,x0 " Lockless
375 tze reset_os_update_count " Won
376 increment ab|rsmeters.reset_os_losses " Lost - meter and retry
377 tra reset_os_loop_retry
378
379 reset_os_update_count:
380 stz stock_temp_1
381 stz stock_temp_2
382 sxl1 stock_temp_2 " To decrement count of OS
383 eax6 0,x6 " Flush call
384 tnz reset_os_update_retry " Yes - don't increment free count
385 stx1 stock_temp_1 " To increment count of free
386 reset_os_update_retry:
387 ldq bb|record_stock.n_free_in_stock " Change count of OS, free
388 lda bb|record_stock.n_free_in_stock " Lockless
389 adla stock_temp_1
390 sbla stock_temp_2
391 stacq bb|record_stock.n_free_in_stock
392 tnz reset_os_update_retry " lost race
393 tra reset_os_loop
394
395
396 "^L
397 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
398 "
399 " check_low_threshold - routine to check whether a stock is below
400 " threshold, and if so to select a volmap page to
401 " replenish it
402 "
403 " tsx7 stock$check_low_threshold
404 " <return if within threshold or no page selected>
405 " <return if below threshold and page selected>
406 "
407 " On entry,
408 " ab -> stock_seg$meters
409 " bb -> stock of interest
410 " bp -> pvte
411 "
412 " On exit,
413 " if page selected, page number is in Areg
414 "
415 " This routine requires the Global Page Table Lock, the per-volume
416 " volume map lock with async state idle
417 "
418 " A volmap page is selected as follows:
419 "
420 " 1. If a page is in memory, it is selected
421 " 2. If no page is in memory, the lowest page which can replenish
422 " the stock to target is selected
423 " 3. Otherwise, the page with the largest number of free records
424 " is selected
425 "
426 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
427
428 check_low_threshold:
429 lxl0 bb|record_stock.n_os_in_stock
430 adlx0 bb|record_stock.n_free_in_stock
431 cmpx0 bb|record_stock.low_threshold " Below threshold
432 tpl 0,x7 " No
433
434 aos ab|rsmeters.low_thresh_detected " Meter
435 stx0 stock_temp_1 " Free + OS
436 ldx0 bb|record_stock.target " Target for Free + OS
437 sbx0 stock_temp_1 " Shortfall
438 stx0 stock_temp_1
439
440 lprpap bp|pvte.volmap_astep " ap -> ASTE for volmap_seg
441 eppap ap|aste_size " ap -> Page Table for volmap_seg
442 lxl0 bb|record_stock.n_volmap_pages
443 stz stock_temp_2
444 sxl0 stock_temp_2
445 lda 0,dl " Page number
446 ldx1 -1,du " First page which can replenish
447 ldx2 -1,du " Page with largest number free
448
449 check_low_mem:
450 ldx0 bb|record_stock.n_free,al " Number free records this page
451 tze check_low_next " None - skip
452 ldq ap|0,al " Qreg = PTW
453 canq ptw.valid,dl " In memory
454 tnz 1,x7 " Yes - exit with page number in Areg
455 cmpx0 stock_temp_1 " Enough to replenish to target
456 tmi check_low_not_enough " No
457 eax1 0,x1 " Found such yet
458 tpl check_low_next " Yes - use first such
459 eax1 0,al " No - this is such
460 tra check_low_next
461
462 check_low_not_enough:
463 eax2 0,x2 " Largest number records so far
464 tpl check_low_highest " One such found
465 eax2 0,al " This is it
466 tra check_low_next
467 check_low_highest:
468 cmpx0 bb|record_stock.n_free,x2 " Is this one higher
469 tmoz check_low_next " No
470 eax2 0,al " Yes
471
472 check_low_next:
473 ada 1,dl " Bump page number
474 cmpa stock_temp_2 " Done all pages
475 tmi check_low_mem " No
476 eaa 0,x1 " First which can replenish
477 tpl check_low_got " One was found
478 eaa 0,x2 " Largest number records
479 tpl check_low_got " Somebody found
480 aos ab|rsmeters.low_thresh_fails " Nobody found - meter
481 tra 0,x7 " And exit
482
483 check_low_got:
484 arl 18 " Page number in AL
485 tra 1,x7
486 "^L
487 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
488 "
489 " recover - routine to recompute counts in the record stock for ESD.
490 " The system may have crashed due to a stock inconsistency,
491 " and this may allow ESD to succeed. Of course, major
492 " trashage to the stock cannot be bypassed.
493 "
494 " On entry,
495 " ab -> stock_seg$meters
496 " bb -> stock of interest
497 " bp -> pvte
498 "
499 " This routine should be called only during ESD
500 "
501 "
502 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
503
504 recover:
505 stz stock_temp_1 " Number free
506 stz stock_temp_2 " Number out-of-service
507
508 sprpbp bb|record_stock.pvtep " Restore pointer to PVTE
509 lxl0 bb|record_stock.stock_offset
510 eppap bb|0,x0 " ap -> stock array
511
512 ldx0 bb|record_stock.n_words_in_stock
513
514 recover_loop:
515 eax0 -1,x0 " Index into stock array
516 tmi recover_done " None left
517 lda ap|0,x0 " Next 2 entries
518 tze recover_loop " Both empty
519 tpl recover_check_upper " Upper not out-of-service
520 aos stock_temp_2 " Upper out-of-service
521 tra recover_check_lower
522 recover_check_upper:
523 cana live_address,du " Upper empty
524 tze recover_check_lower " Yes
525 aos stock_temp_1 " No
526 recover_check_lower:
527 cana os_address,dl " Lower out-of-service
528 tze recover_check_lower_inuse " No
529 aos stock_temp_2 " Yes
530 tra recover_loop
531
532 recover_check_lower_inuse:
533 cana live_address,dl " Lower empty
534 tze recover_loop " Yes
535 aos stock_temp_1 " No
536 tra recover_loop
537
538 recover_done:
539 lda stock_temp_1 " Number free
540 als 18 " Align
541 ora stock_temp_2 " Merge in number out-of-service
542 sta bb|record_stock.n_free_in_stock " And set count into stock
543
544 tra 0,x7
545
546 end