;;; -*- Mode:LISP; Package:SYSTEM-INTERNALS; Base:8; Readtable:ZL -*-

(defvar *page-cleaner-ppd-index*)

(defun clean-pages ()
  (let ((ppd-base (%region-origin physical-page-data))
	(ppd-index *page-cleaner-ppd-index*)
	(pht-base (%region-origin page-table-area))
	(phys-pages (floor (aref #'sys:system-communication-area sys:%sys-com-memory-size) 256.))
	pht-adr
	(disk-page-reads-loc '%count-disk-page-reads)
	(disk-page-writes-loc '%count-disk-page-writes)
	disk-page-reads
	disk-page-writes
	(ccwp %DISK-RQ-CCW-LIST)
	(ccwstart %disk-rq-ccw-list)
	;;(ccwend (* page-rqb-size 2))
	(ccwend (+ %disk-rq-ccw-list 2))
	vpage-start
	(n-pages 0)
	(local-page-offset page-offset)
	(region-bits-origin (%region-origin region-bits))
	)
    (coerce-to-meter-location disk-page-reads-loc)
    (coerce-to-meter-location disk-page-writes-loc)
    (setq disk-page-reads (%p-ldb (byte 16. 0) disk-page-reads-loc))
    (setq disk-page-writes (%p-ldb (byte 16. 0) disk-page-writes-loc))
    ;;find next dirty page, but only if it is one of the next N pages
    (do ((i 0 (1+ i)))
	((= i 5)
	 (setq *page-cleaner-ppd-index* ppd-index)
	 (return-from clean-pages nil))
      (let ((pht-index (%p-ldb (byte 16. 0) (+ ppd-base ppd-index))))
	(when (not (= pht-index #o177777))
	  (setq pht-adr (+ pht-index pht-base))
	  (when (and (= (%p-ldb #.%%pht1-valid-bit pht-adr) 1)
		     (not (= (%p-ldb #.%%pht1-swap-status-code pht-adr) #.%pht-swap-status-wired))
		     (or (= (%p-ldb #.%%pht1-modified-bit pht-adr) 1)
			 (= (%p-ldb #.%%pht2-map-status-code (1+ pht-adr)) #.%pht-map-status-read-write)))
	    (return nil))))
      (incf ppd-index)
      (when (= ppd-index phys-pages)
	(setq ppd-index 0)))
    ;;get here with PHT-ADR pointing to the PHT entry for first dirty page
    ;;we want to write out this, and any following dirty virtual pages
    (wire-page-rqb)
    (setq vpage-start (%p-ldb #.%%pht1-virtual-page-number pht-adr))
    (do ((vpage vpage-start (+ vpage 1))
	 (vadr (lsh vpage-start 8) (%make-pointer-offset #.dtp-fix vadr #o400)))
	(())
      (let ((page-status (%page-status vadr))
	    (logical-adr (%physical-address vadr)))
	(when (or (null page-status)
		  (not (= 1 (ldb #.%%pht1-modified-bit page-status)))
		  (null logical-adr))
	  (return nil))
	(incf n-pages)
	(setf (aref page-rqb ccwp) (+ logical-adr 1))
	(setf (aref page-rqb (+ ccwp 1)) (lsh logical-adr -16.))
	(incf ccwp 2)
	(when (= ccwp ccwend)
	  (return nil))
	))

    (when (= ccwp ccwstart)
      (ferror nil "page got unmodified!!"))

    (setf (ldb (byte 1 0) (aref page-rqb (- ccwp 2))) 0)

    (when (or (not (= disk-page-reads (%p-ldb (byte 16. 0) disk-page-reads-loc)))
	      (not (= disk-page-writes (%p-ldb (byte 16. 0) disk-page-writes-loc))))
      (ferror nil "did some paging at a bad time"))

    (disk-write-wired page-rqb 0 (+ vpage-start local-page-offset))

    (when (or (not (= disk-page-reads (%p-ldb (byte 16. 0) disk-page-reads-loc)))
	      (not (= disk-page-writes (%p-ldb (byte 16. 0) disk-page-writes-loc))))
      (ferror nil "did some paging at a terrible time"))

    (do ((vadr (lsh page-start 8) (%make-pointer-offset #.dtp-fix vadr #o400))
	 (i 0 (1+ i)))
	((= i n-pages))
      (let ((page-status (%page-status vadr)))
	(when (null page-status)
	  (ferror nil "page slipped away!!"))
	(let ((swap-status (ldb #.%%pht1-swap-status-code page-status)))
	  (%change-page-status vadr
			       (+ 1_23. swap-status)
			       (%p-ldb #.%%region-map-bits (+ region-bits-origin
							      (%region-number vadr)))))))))
    
	       
      
