Annotation of kernel/vm/vm_pageout.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /* 
        !            26:  * Mach Operating System
        !            27:  * Copyright (c) 1987 Carnegie-Mellon University
        !            28:  * All rights reserved.  The CMU software License Agreement specifies
        !            29:  * the terms and conditions for use and redistribution.
        !            30:  */
        !            31: /*
        !            32:  *     File:   vm/vm_pageout.c
        !            33:  *     Author: Avadis Tevanian, Jr., Michael Wayne Young
        !            34:  *
        !            35:  *     Copyright (C) 1985, Avadis Tevanian, Jr., Michael Wayne Young
        !            36:  *
        !            37:  *     The proverbial page-out daemon.
        !            38:  */
        !            39: 
        !            40: #import <vm/vm_page.h>
        !            41: #import <vm/pmap.h>
        !            42: #import <vm/vm_object.h>
        !            43: #import <vm/vm_pageout.h>
        !            44: #import <mach/vm_statistics.h>
        !            45: #import <mach/vm_param.h>
        !            46: #import <kern/thread.h>
        !            47: #import <machine/spl.h>
        !            48: 
        !            49: simple_lock_data_t     vm_pages_needed_lock;
        !            50: 
        !            51: int    vm_pages_needed;                /* Event on which pageout daemon sleeps */
        !            52: int    vm_pageout_free_min = 0;        /* Stop pageout to wait for pagers at this free level */
        !            53: 
        !            54: int    vm_page_free_min_sanity = 256*1024;
        !            55: 
        !            56: #if    MACH_VM_DEBUG
        !            57: long   vm_page_total_pages = 0;
        !            58: long   local_total_pages;
        !            59: #endif /* MACH_VM_DEBUG */
        !            60: 
        !            61: /*
        !            62:  *     vm_pageout_scan does the dirty work for the pageout daemon.
        !            63:  */
        !            64: boolean_t
        !            65: vm_pageout_scan()
        !            66: {
        !            67:        register vm_page_t      m;
        !            68:        register int            page_shortage;
        !            69:        register int            s;
        !            70:        register int            pages_freed = 0;
        !            71:        register int            pages_cleaned = 0;
        !            72:        boolean_t               free_pages;
        !            73:        boolean_t               did_work = FALSE;
        !            74: #if    MACH_VM_DEBUG
        !            75:        int                     dbg_intoa_pages = 0;
        !            76:        int                     dbg_pages_needed = 0;
        !            77:        int                     dbg_pages_cleaned = 0;
        !            78: #endif /* MACH_VM_DEBUG */
        !            79: 
        !            80: 
        !            81:        /*
        !            82:         *      Only continue when we want more pages to be "free"
        !            83:         */
        !            84:                s = splimp();
        !            85:                simple_lock(&vm_page_queue_free_lock);
        !            86: 
        !            87:                free_pages = FALSE;
        !            88:                if (vm_page_free_count <= vm_page_free_min) {
        !            89:                        free_pages = TRUE;
        !            90:                        /*
        !            91:                         *      See whether the physical mapping system
        !            92:                         *      knows of any pages which are not being used.
        !            93:                         */
        !            94:                 
        !            95:                        simple_unlock(&vm_page_queue_free_lock);
        !            96:                        splx(s);
        !            97: 
        !            98:                        /*
        !            99:                         *      And be sure the pmap system is updated so
        !           100:                         *      we can scan the inactive queue.
        !           101:                         */
        !           102: 
        !           103:                        pmap_update();
        !           104:                }
        !           105:                else {
        !           106:                        simple_unlock(&vm_page_queue_free_lock);
        !           107:                        splx(s);
        !           108:                }
        !           109: 
        !           110:        /*
        !           111:         *      Acquire the resident page system lock,
        !           112:         *      as we may be changing what's resident quite a bit.
        !           113:         */
        !           114:        vm_page_lock_queues();
        !           115: 
        !           116:        /*
        !           117:         *      Start scanning the inactive queue for pages we can free.
        !           118:         *      We keep scanning until we have enough free pages or
        !           119:         *      we have scanned through the entire queue.  If we
        !           120:         *      encounter dirty pages, we start cleaning them.
        !           121:         */
        !           122: 
        !           123:        pages_freed = 0;
        !           124:        m = (vm_page_t) queue_first(&vm_page_queue_inactive);
        !           125:        while (free_pages &&
        !           126:            !queue_end(&vm_page_queue_inactive, (queue_entry_t) m)) {
        !           127:                vm_page_t       next;
        !           128: 
        !           129:                        s = splimp();
        !           130:                        simple_lock(&vm_page_queue_free_lock);
        !           131:                        if ((vm_page_free_count + pages_cleaned) >= vm_page_free_target) {
        !           132:                                simple_unlock(&vm_page_queue_free_lock);
        !           133:                                splx(s);
        !           134:                                break;
        !           135:                        }
        !           136:                        simple_unlock(&vm_page_queue_free_lock);
        !           137:                        splx(s);
        !           138: 
        !           139: #if 0
        !           140:                if (pmap_is_referenced(VM_PAGE_TO_PHYS(m)) &&
        !           141:                    (vm_page_inactive_target < vm_page_inactive_count))
        !           142: #else
        !           143:                if (pmap_is_referenced(VM_PAGE_TO_PHYS(m)))
        !           144: #endif
        !           145:                {
        !           146:                        next = (vm_page_t) queue_next(&m->pageq);
        !           147:                        vm_page_activate(m);
        !           148:                        vm_stat.reactivations++; 
        !           149:                        m = next;
        !           150: #if    MACH_VM_DEBUG
        !           151:                        dbg_intoa_pages++;
        !           152: #endif /* MACH_VM_DEBUG */
        !           153:                        continue;
        !           154:                }
        !           155: 
        !           156:                if (m->clean) {
        !           157:                                register vm_object_t    object;
        !           158: 
        !           159:                                next = (vm_page_t) queue_next(&m->pageq);
        !           160:                                object = m->object;
        !           161:                                if (!vm_object_lock_try(object)) {
        !           162:                                        /*
        !           163:                                         *      Can't lock object -
        !           164:                                         *      skip page.
        !           165:                                         */
        !           166:                                        m = next;
        !           167:                                        continue;
        !           168:                                }
        !           169:                                did_work = TRUE;
        !           170:                                m->busy = TRUE;
        !           171:                                vm_page_unlock_queues();
        !           172: 
        !           173:                                pmap_remove_all(VM_PAGE_TO_PHYS(m));
        !           174:                                vm_page_lock_queues();
        !           175:                                m->busy = FALSE;
        !           176:                                PAGE_WAKEUP(m);
        !           177:                        
        !           178:                                next = (vm_page_t) queue_next(&m->pageq);
        !           179:                                vm_page_addfree(m);
        !           180:                                pages_freed++;
        !           181: #if    MACH_VM_DEBUG
        !           182:                        --dbg_pages_needed;
        !           183: #endif /* MACH_VM_DEBUG */
        !           184:                                vm_object_unlock(object);
        !           185:                                m = next;
        !           186:                }
        !           187:                else {
        !           188:                        /*
        !           189:                         *      If a page is dirty, then it is either
        !           190:                         *      being washed (but not yet cleaned)
        !           191:                         *      or it is still in the laundry.  If it is
        !           192:                         *      still in the laundry, then we start the
        !           193:                         *      cleaning operation.
        !           194:                         */
        !           195: 
        !           196: #if    0 && MACH_VM_DEBUG
        !           197:        kprintf("     : pulled dirty page off inactive list\n");
        !           198: #endif /* MACH_VM_DEBUG */
        !           199:                        if (m->laundry) {
        !           200:                                /*
        !           201:                                 *      Clean the page and remove it from the
        !           202:                                 *      laundry.
        !           203:                                 *
        !           204:                                 *      We set the busy bit to cause
        !           205:                                 *      potential page faults on this page to
        !           206:                                 *      block.
        !           207:                                 *
        !           208:                                 *      And we set pageout-in-progress to keep
        !           209:                                 *      the object from disappearing during
        !           210:                                 *      pageout.  This guarantees that the
        !           211:                                 *      page won't move from the inactive
        !           212:                                 *      queue.  (However, any other page on
        !           213:                                 *      the inactive queue may move!)
        !           214:                                 */
        !           215: 
        !           216:                                register vm_object_t    object;
        !           217:                                register vm_pager_t     pager;
        !           218:                                boolean_t       pageout_succeeded;
        !           219: 
        !           220: #if    0 && MACH_VM_DEBUG
        !           221:        kprintf("    cleaning dirty page off inactive list\n");
        !           222: #endif /* MACH_VM_DEBUG */
        !           223:                                object = m->object;
        !           224:                                if (!vm_object_lock_try(object)) {
        !           225:                                        /*
        !           226:                                         *      Skip page if we can't lock
        !           227:                                         *      its object
        !           228:                                         */
        !           229:                                        m = (vm_page_t) queue_next(&m->pageq);
        !           230:                                        continue;
        !           231:                                }
        !           232: 
        !           233:                                m->busy = TRUE;
        !           234:                                vm_stat.pageouts++;
        !           235: 
        !           236:                                /*
        !           237:                                 *      Try to collapse the object before
        !           238:                                 *      making a pager for it.  We must
        !           239:                                 *      unlock the page queues first.
        !           240:                                 */
        !           241:                                vm_page_unlock_queues();
        !           242: 
        !           243:                                did_work = TRUE;
        !           244:                                /*
        !           245:                                 * Moved this call from inside the queue lock
        !           246:                                 * to prevent the following scenario:
        !           247:                                 * remove_all -> pmap_collapse ->
        !           248:                                 * kmem_free -> vm_page_lock_queues
        !           249:                                 */
        !           250:                                pmap_remove_all(VM_PAGE_TO_PHYS(m));
        !           251: 
        !           252:                                vm_object_collapse(object);
        !           253: 
        !           254:                                object->paging_in_progress++;
        !           255: 
        !           256:                                vm_object_unlock(object);
        !           257: 
        !           258: 
        !           259:                                /*
        !           260:                                 *      Do a wakeup here in case the following
        !           261:                                 *      operations block.
        !           262:                                 */
        !           263:                                thread_wakeup(&vm_page_free_count);
        !           264: 
        !           265:                                /*
        !           266:                                 *      If there is no pager for the page,
        !           267:                                 *      use the default pager.  If there's
        !           268:                                 *      no place to put the page at the
        !           269:                                 *      moment, leave it in the laundry and
        !           270:                                 *      hope that there will be paging space
        !           271:                                 *      later.
        !           272:                                 */
        !           273: 
        !           274:                                if ((pager = object->pager) == vm_pager_null) {
        !           275:                                        pager = (vm_pager_t)vm_pager_allocate(
        !           276:                                                        object->size);
        !           277:                                        if (pager != vm_pager_null) {
        !           278:                                                vm_object_setpager(object,
        !           279:                                                        pager, 0, FALSE);
        !           280:                                        }
        !           281:                                }
        !           282: 
        !           283:                                pageout_succeeded = FALSE;
        !           284:                                if (pager != vm_pager_null) {
        !           285:                                    if (vm_pager_put(pager, m) == PAGER_SUCCESS) {
        !           286:                                        pageout_succeeded = TRUE;
        !           287: #if    MACH_VM_DEBUG
        !           288:                                        dbg_pages_cleaned++;
        !           289: #endif /* MACH_VM_DEBUG */
        !           290:                                        pages_cleaned++;
        !           291:                                    }
        !           292:                                }
        !           293: 
        !           294:                                vm_object_lock(object);
        !           295:                                vm_page_lock_queues();
        !           296: 
        !           297:                                /*
        !           298:                                 *      If page couldn't be paged out, then
        !           299:                                 *      reactivate the page so it doesn't
        !           300:                                 *      clog the inactive list.  (We will try
        !           301:                                 *      paging out it again later).
        !           302:                                 */
        !           303:                                next = (vm_page_t) queue_next(&m->pageq);
        !           304:                                if (pageout_succeeded)
        !           305:                                        m->laundry = FALSE;
        !           306:                                else
        !           307:                                        vm_page_activate(m);
        !           308: 
        !           309: /* Why are we doing this. Was it not cleared when the mappings were removed
        !           310:  * Is this here for a different arch */
        !           311:                                pmap_clear_reference(VM_PAGE_TO_PHYS(m));
        !           312:                                        m->busy = FALSE;
        !           313:                                        PAGE_WAKEUP(m);
        !           314: 
        !           315:                                        object->paging_in_progress--;
        !           316:                                        thread_wakeup(object);
        !           317:                                vm_object_unlock(object);
        !           318:                                m = next;
        !           319:                        }
        !           320:                        else
        !           321:                                m = (vm_page_t) queue_next(&m->pageq);
        !           322:                }
        !           323:        }
        !           324: 
        !           325:        /*
        !           326:         *      Compute the page shortage.  If we are still very low on memory
        !           327:         *      be sure that we will move a minimal amount of pages from active
        !           328:         *      to inactive.
        !           329:         */
        !           330: 
        !           331:        page_shortage = vm_page_inactive_target - vm_page_inactive_count;
        !           332:        page_shortage -= vm_page_free_count;
        !           333: 
        !           334: //     if ((page_shortage <= 0) && (pages_freed == 0))
        !           335: //             page_shortage = 1;
        !           336: 
        !           337:        while (page_shortage > 0) {
        !           338:                /*
        !           339:                 *      Move some more pages from active to inactive.
        !           340:                 */
        !           341: 
        !           342:                if (queue_empty(&vm_page_queue_active)) {
        !           343:                        break;
        !           344:                }
        !           345:                did_work = TRUE;
        !           346:                m = (vm_page_t) queue_first(&vm_page_queue_active);
        !           347:                vm_page_deactivate(m);
        !           348:                page_shortage--;
        !           349:        }
        !           350: 
        !           351:        vm_page_unlock_queues();
        !           352: 
        !           353:        if (!pages_cleaned && !pages_freed && did_work) {
        !           354:                /*
        !           355:                 * We did not issue any IO in the loop and did not free any
        !           356:                 * pages. Yield to someone before proceeding so that we do
        !           357:                 * not go compute bound, which will prevent the threads trying
        !           358:                 * to do a biodone() from running. If that does not happen,
        !           359:                 * no forward progress would be made.
        !           360:                 */
        !           361:                thread_will_wait(current_thread());
        !           362:                thread_set_timeout(2);  /* 2 ticks */
        !           363:                thread_block();
        !           364:        }
        !           365: 
        !           366:        return did_work;
        !           367: }
        !           368: 
        !           369: 
        !           370: /*
        !           371:  *     vm_pageout is the high level pageout daemon.
        !           372:  */
        !           373: 
        !           374: void vm_pageout()
        !           375: {
        !           376:        thread_t        self = current_thread();
        !           377:        boolean_t       vm_pageout_scan_did_work = TRUE;
        !           378: 
        !           379:        stack_privilege(self);
        !           380:        self->sched_pri = self->priority = MAXPRI_USER;
        !           381:        self->policy = POLICY_FIXEDPRI;
        !           382:        self->sched_data = min_quantum;
        !           383:        self->vm_privilege = TRUE;
        !           384: 
        !           385:        (void) spl0();
        !           386: 
        !           387:        /*
        !           388:         *      Initialize some paging parameters.
        !           389:         */
        !           390: 
        !           391:        if (vm_page_free_min == 0) {
        !           392: //             vm_page_free_min = vm_page_free_count / 20;
        !           393:                /*
        !           394:                ** This is 2.00% of available free pages
        !           395:                */
        !           396:                vm_page_free_min = vm_page_free_count / 50;
        !           397:                if (vm_page_free_min < 3)
        !           398:                        vm_page_free_min = 3;
        !           399: 
        !           400:                if (vm_page_free_min*PAGE_SIZE > vm_page_free_min_sanity)
        !           401:                        vm_page_free_min = vm_page_free_min_sanity/PAGE_SIZE;
        !           402:        }
        !           403: 
        !           404:        if (vm_page_free_reserved == 0) {
        !           405:                /*
        !           406:                ** This is 0.50% of available free pages
        !           407:                */
        !           408:                if ((vm_page_free_reserved = vm_page_free_min / 4) < 3)
        !           409:                        vm_page_free_reserved = 3;
        !           410:        }
        !           411:        if (vm_pageout_free_min == 0) {
        !           412:                if ((vm_pageout_free_min = vm_page_free_reserved / 2) > 10)
        !           413:                        vm_pageout_free_min = 10;
        !           414:        }
        !           415: 
        !           416:        if (vm_page_free_target == 0)
        !           417: //             vm_page_free_target = (vm_page_free_min * 4) / 3;
        !           418:                /*
        !           419:                ** This is 8.00% of available free pages
        !           420:                */
        !           421:                vm_page_free_target = vm_page_free_min * 4;
        !           422: 
        !           423:        if (vm_page_inactive_target == 0)
        !           424:                vm_page_inactive_target = vm_page_free_count / 3;
        !           425: 
        !           426:        if (vm_page_free_target <= vm_page_free_min)
        !           427:                vm_page_free_target = vm_page_free_min + 1;
        !           428: 
        !           429:        if (vm_page_inactive_target <= vm_page_free_target)
        !           430:                vm_page_inactive_target = vm_page_free_target + 1;
        !           431: 
        !           432: #if    MACH_VM_DEBUG
        !           433:        kprintf("vm_pageout: free_count=0x%X\n",
        !           434:            vm_page_free_count);
        !           435:        kprintf("vm_pageout: free_min=0x%X, free_reserved=0x%X\n",
        !           436:            vm_page_free_min, vm_page_free_reserved);
        !           437:        kprintf("vm_pageout: free_target=0x%X, inactive_target=0x%X\n",
        !           438:            vm_page_free_target, vm_page_inactive_target);
        !           439: #endif
        !           440: 
        !           441:        /*
        !           442:         *      The pageout daemon is never done, so loop
        !           443:         *      forever.
        !           444:         */
        !           445: 
        !           446:        simple_lock(&vm_pages_needed_lock);
        !           447:        while (TRUE) {
        !           448:                if (!vm_pageout_scan_did_work)
        !           449:                        thread_sleep(&vm_pages_needed,
        !           450:                                     &vm_pages_needed_lock, FALSE);
        !           451:                else
        !           452:                if ((vm_page_free_count > vm_page_free_min) &&
        !           453:                    ((vm_page_free_count >= vm_page_free_target) ||
        !           454:                     (vm_page_inactive_count > vm_page_inactive_target)))
        !           455:                        thread_sleep(&vm_pages_needed,
        !           456:                                     &vm_pages_needed_lock, FALSE);
        !           457:                else{
        !           458:                        simple_unlock(&vm_pages_needed_lock);
        !           459:                }
        !           460:                vm_pageout_scan_did_work = vm_pageout_scan();
        !           461:                simple_lock(&vm_pages_needed_lock);
        !           462:                thread_wakeup(&vm_page_free_count);
        !           463:        }
        !           464: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.