Annotation of XNU/osfmk/default_pager/dp_memory_object.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:  * @OSF_COPYRIGHT@
        !            24:  */
        !            25: /* 
        !            26:  * Mach Operating System
        !            27:  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
        !            28:  * All Rights Reserved.
        !            29:  * 
        !            30:  * Permission to use, copy, modify and distribute this software and its
        !            31:  * documentation is hereby granted, provided that both the copyright
        !            32:  * notice and this permission notice appear in all copies of the
        !            33:  * software, derivative works or modified versions, and any portions
        !            34:  * thereof, and that both notices appear in supporting documentation.
        !            35:  * 
        !            36:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            37:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !            38:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            39:  * 
        !            40:  * Carnegie Mellon requests users of this software to return to
        !            41:  * 
        !            42:  *  Software Distribution Coordinator  or  [email protected]
        !            43:  *  School of Computer Science
        !            44:  *  Carnegie Mellon University
        !            45:  *  Pittsburgh PA 15213-3890
        !            46:  * 
        !            47:  * any improvements or extensions that they make and grant Carnegie Mellon
        !            48:  * the rights to redistribute these changes.
        !            49:  */
        !            50: 
        !            51: /*
        !            52:  *     Default Pager.
        !            53:  *             Memory Object Management.
        !            54:  */
        !            55: 
        !            56: #include "default_pager_internal.h"
        !            57: #include <mach/memory_object_server.h>
        !            58: #include <vm/vm_pageout.h> /* include for upl_t */
        !            59: 
        !            60: 
        !            61: /*
        !            62:  * List of all vstructs.  A specific vstruct is
        !            63:  * found directly via its port, this list is
        !            64:  * only used for monitoring purposes by the
        !            65:  * default_pager_object* calls and by ps_delete
        !            66:  * when abstract memory objects must be scanned
        !            67:  * to remove any live storage on a segment which
        !            68:  * is to be removed.
        !            69:  */
        !            70: struct vstruct_list_head       vstruct_list;
        !            71: 
        !            72: void vstruct_list_insert(vstruct_t vs);        /* forward */
        !            73: 
        !            74: void
        !            75: vstruct_list_insert(
        !            76:        vstruct_t vs)
        !            77: {
        !            78:        VSL_LOCK();
        !            79:        queue_enter(&vstruct_list.vsl_queue, vs, vstruct_t, vs_links);
        !            80:        vstruct_list.vsl_count++;
        !            81:        VSL_UNLOCK();
        !            82: }
        !            83: 
        !            84: void vstruct_list_delete(vstruct_t vs);        /* forward */
        !            85: 
        !            86: void
        !            87: vstruct_list_delete(
        !            88:        vstruct_t vs)
        !            89: {
        !            90:        queue_remove(&vstruct_list.vsl_queue, vs, vstruct_t, vs_links);
        !            91:        vstruct_list.vsl_count--;
        !            92: }
        !            93: 
        !            94: /*
        !            95:  * We use the sequence numbers on requests to regulate
        !            96:  * our parallelism.  In general, we allow multiple reads and writes
        !            97:  * to proceed in parallel, with the exception that reads must
        !            98:  * wait for previous writes to finish.  (Because the kernel might
        !            99:  * generate a data-request for a page on the heels of a data-write
        !           100:  * for the same page, and we must avoid returning stale data.)
        !           101:  * terminate requests wait for proceeding reads and writes to finish.
        !           102:  */
        !           103: 
        !           104: unsigned int   default_pager_total = 0;                /* debugging */
        !           105: unsigned int   default_pager_wait_seqno = 0;           /* debugging */
        !           106: unsigned int   default_pager_wait_read = 0;            /* debugging */
        !           107: unsigned int   default_pager_wait_write = 0;           /* debugging */
        !           108: unsigned int   default_pager_wait_refs = 0;            /* debugging */
        !           109: 
        !           110: void vs_async_wait(vstruct_t); /* forward */
        !           111: 
        !           112: void
        !           113: vs_async_wait(
        !           114:        vstruct_t       vs)
        !           115: {
        !           116:        static char here[] = "vs_async_wait";
        !           117: 
        !           118:        ASSERT(vs->vs_async_pending >= 0);
        !           119:        while (vs->vs_async_pending > 0) {
        !           120:                vs->vs_waiting_async = TRUE;
        !           121:                assert_wait(&vs->vs_waiting_async, THREAD_UNINT);
        !           122:                VS_UNLOCK(vs);
        !           123:                thread_block((void (*)(void))0);
        !           124:                VS_LOCK(vs);
        !           125:        }
        !           126:        ASSERT(vs->vs_async_pending == 0);
        !           127: }
        !           128: 
        !           129: #if    PARALLEL
        !           130: void vs_lock(vstruct_t, mach_port_seqno_t);
        !           131: void vs_unlock(vstruct_t);
        !           132: void vs_start_read(vstruct_t);
        !           133: void vs_wait_for_readers(vstruct_t);
        !           134: void vs_finish_read(vstruct_t);
        !           135: void vs_start_write(vstruct_t);
        !           136: void vs_wait_for_writers(vstruct_t);
        !           137: void vs_finish_write(vstruct_t);
        !           138: void vs_wait_for_refs(vstruct_t);
        !           139: void vs_finish_refs(vstruct_t);
        !           140: 
        !           141: /* 
        !           142:  * Waits for correct sequence number.  Leaves pager locked.
        !           143:  * JMM - Sequence numbers guarantee ordering, but in a preemptible
        !           144:  *       kernel, they are generated without locks, and so their
        !           145:  *       generation order is undefined (and therefore unreliable).
        !           146:  *      Since we ned to fix this anyway, and I needed to get rid
        !           147:  *      rid of asymmetry in the interface definitions, I have
        !           148:  *       punted this to here.
        !           149:  */
        !           150: void
        !           151: vs_lock(
        !           152:        vstruct_t               vs,
        !           153:        mach_port_seqno_t       seqno)
        !           154: {
        !           155:        default_pager_total++;
        !           156:        VS_LOCK(vs);
        !           157: 
        !           158:        seqno = vs->vs_next_seqno++;
        !           159: 
        !           160:        while (vs->vs_seqno != seqno) {
        !           161:                default_pager_wait_seqno++;
        !           162:                vs->vs_waiting_seqno = TRUE;
        !           163:                assert_wait(&vs->vs_waiting_seqno, THREAD_UNINT);
        !           164:                VS_UNLOCK(vs);
        !           165:                thread_block((void (*)(void))0);
        !           166:                VS_LOCK(vs);
        !           167:        }
        !           168: }
        !           169: 
        !           170: /*
        !           171:  * Increments sequence number and unlocks pager.
        !           172:  */
        !           173: void
        !           174: vs_unlock(vstruct_t vs)
        !           175: {
        !           176:        boolean_t need_wakeups = vs->vs_waiting_seqno;
        !           177: 
        !           178:        vs->vs_waiting_seqno = FALSE;
        !           179:        vs->vs_seqno++;
        !           180:        VS_UNLOCK(vs);
        !           181:        if (need_wakeups)
        !           182:                thread_wakeup(&vs->vs_waiting_seqno);
        !           183: }
        !           184: 
        !           185: /* 
        !           186:  * Start a read - one more reader.  Pager must be locked.
        !           187:  */
        !           188: void
        !           189: vs_start_read(
        !           190:        vstruct_t vs)
        !           191: {
        !           192:        vs->vs_readers++;
        !           193: }
        !           194: 
        !           195: /*
        !           196:  * Wait for readers.  Unlocks and relocks pager if wait needed.
        !           197:  */
        !           198: void
        !           199: vs_wait_for_readers(
        !           200:        vstruct_t vs)
        !           201: {
        !           202:        while (vs->vs_readers != 0) {
        !           203:                default_pager_wait_read++;
        !           204:                vs->vs_waiting_read = TRUE;
        !           205:                assert_wait(&vs->vs_waiting_read, THREAD_UNINT);
        !           206:                VS_UNLOCK(vs);
        !           207:                thread_block((void (*)(void))0);
        !           208:                VS_LOCK(vs);
        !           209:        }
        !           210: }
        !           211: 
        !           212: /*
        !           213:  * Finish a read.  Pager is unlocked and returns unlocked.
        !           214:  */
        !           215: void
        !           216: vs_finish_read(
        !           217:        vstruct_t vs)
        !           218: {
        !           219:        VS_LOCK(vs);
        !           220:        if (--vs->vs_readers == 0) {
        !           221:                boolean_t need_wakeups = vs->vs_waiting_read;
        !           222: 
        !           223:                vs->vs_waiting_read = FALSE;
        !           224:                VS_UNLOCK(vs);
        !           225:                if (need_wakeups)
        !           226:                        thread_wakeup(&vs->vs_waiting_read);
        !           227:        } else
        !           228:                VS_UNLOCK(vs);
        !           229: }
        !           230: 
        !           231: /*
        !           232:  * Start a write - one more writer.  Pager must be locked.
        !           233:  */
        !           234: void
        !           235: vs_start_write(
        !           236:        vstruct_t vs)
        !           237: {
        !           238:        vs->vs_writers++;
        !           239: }
        !           240: 
        !           241: /* 
        !           242:  * Wait for writers.  Unlocks and relocks pager if wait needed.
        !           243:  */
        !           244: void
        !           245: vs_wait_for_writers(
        !           246:        vstruct_t vs)
        !           247: {
        !           248:        while (vs->vs_writers != 0) {
        !           249:                default_pager_wait_write++;
        !           250:                vs->vs_waiting_write = TRUE;
        !           251:                assert_wait(&vs->vs_waiting_write, THREAD_UNINT);
        !           252:                VS_UNLOCK(vs);
        !           253:                thread_block((void (*)(void))0);
        !           254:                VS_LOCK(vs);
        !           255:        }
        !           256:        vs_async_wait(vs);
        !           257: }
        !           258: 
        !           259: /* This is to be used for the transfer from segment code ONLY */
        !           260: /* The transfer code holds off vs destruction by keeping the  */
        !           261: /* vs_async_wait count non-zero.  It will not ocnflict with   */
        !           262: /* other writers on an async basis because it only writes on  */
        !           263: /* a cluster basis into fresh (as of sync time) cluster locations */
        !           264: void 
        !           265: vs_wait_for_sync_writers(
        !           266:         vstruct_t vs)
        !           267: {
        !           268:         while (vs->vs_writers != 0) {
        !           269:                 default_pager_wait_write++;
        !           270:                vs->vs_waiting_write = TRUE;
        !           271:                 assert_wait(&vs->vs_waiting_write, THREAD_UNINT);
        !           272:                 VS_UNLOCK(vs);
        !           273:                 thread_block((void (*)(void))0);
        !           274:                 VS_LOCK(vs);
        !           275:         }
        !           276: }       
        !           277: 
        !           278: 
        !           279: /*
        !           280:  * Finish a write.  Pager is unlocked and returns unlocked.
        !           281:  */
        !           282: void
        !           283: vs_finish_write(
        !           284:        vstruct_t vs)
        !           285: {
        !           286:        VS_LOCK(vs);
        !           287:        if (--vs->vs_writers == 0) {
        !           288:                boolean_t need_wakeups = vs->vs_waiting_write;
        !           289: 
        !           290:                vs->vs_waiting_write = FALSE;
        !           291:                VS_UNLOCK(vs);
        !           292:                if (need_wakeups)
        !           293:                        thread_wakeup(&vs->vs_waiting_write);
        !           294:        } else
        !           295:                VS_UNLOCK(vs);
        !           296: }
        !           297: 
        !           298: /*
        !           299:  * Wait for concurrent default_pager_objects.
        !           300:  * Unlocks and relocks pager if wait needed.
        !           301:  */
        !           302: void
        !           303: vs_wait_for_refs(
        !           304:        vstruct_t vs)
        !           305: {
        !           306:        while (vs->vs_name_refs == 0) {
        !           307:                default_pager_wait_refs++;
        !           308:                vs->vs_waiting_refs = TRUE;
        !           309:                assert_wait(&vs->vs_waiting_refs, THREAD_UNINT);
        !           310:                VS_UNLOCK(vs);
        !           311:                thread_block((void (*)(void))0);
        !           312:                VS_LOCK(vs);
        !           313:        }
        !           314: }
        !           315: 
        !           316: /*
        !           317:  * Finished creating name refs - wake up waiters.
        !           318:  */
        !           319: void
        !           320: vs_finish_refs(
        !           321:        vstruct_t vs)
        !           322: {
        !           323:        boolean_t need_wakeups = vs->vs_waiting_refs;
        !           324:        vs->vs_waiting_refs = FALSE;
        !           325:        if (need_wakeups)
        !           326:                thread_wakeup(&vs->vs_waiting_refs);
        !           327: }
        !           328: 
        !           329: #else  /* PARALLEL */
        !           330: 
        !           331: #define        vs_lock(vs,seqno)
        !           332: #define        vs_unlock(vs)
        !           333: #define        vs_start_read(vs)
        !           334: #define        vs_wait_for_readers(vs)
        !           335: #define        vs_finish_read(vs)
        !           336: #define        vs_start_write(vs)
        !           337: #define        vs_wait_for_writers(vs)
        !           338: #define        vs_wait_for_sync_writers(vs)
        !           339: #define        vs_finish_write(vs)
        !           340: #define vs_wait_for_refs(vs)
        !           341: #define vs_finish_refs(vs)
        !           342: 
        !           343: #endif /* PARALLEL */
        !           344: 
        !           345: vstruct_t vs_object_create(vm_size_t); /* forward */
        !           346: 
        !           347: vstruct_t
        !           348: vs_object_create(
        !           349:        vm_size_t size)
        !           350: {
        !           351:        vstruct_t       vs;
        !           352:        static char here[] = "vs_object_create";
        !           353: 
        !           354:        /*
        !           355:         * Allocate a vstruct. If there are any problems, then report them
        !           356:         * to the console.
        !           357:         */
        !           358:        vs = ps_vstruct_create(size);
        !           359:        if (vs == VSTRUCT_NULL) {
        !           360:                dprintf(("vs_object_create: unable to allocate %s\n",
        !           361:                         "-- either run swapon command or reboot"));
        !           362:                return VSTRUCT_NULL;
        !           363:        }
        !           364: 
        !           365:        return vs;
        !           366: }
        !           367: 
        !           368: mach_port_urefs_t default_pager_max_urefs = 10000;
        !           369: 
        !           370: /*
        !           371:  * Check user reference count on memory object control port.
        !           372:  * Vstruct must be locked.
        !           373:  * Unlocks and re-locks vstruct if needs to call kernel.
        !           374:  */
        !           375: void vs_check_request(vstruct_t, MACH_PORT_FACE);      /* forward */
        !           376: 
        !           377: void
        !           378: vs_check_request(
        !           379:        vstruct_t       vs,
        !           380:        MACH_PORT_FACE  control_port)
        !           381: {
        !           382:        mach_port_delta_t delta;
        !           383:        kern_return_t   kr;
        !           384:        static char     here[] = "vs_check_request";
        !           385: 
        !           386:        if (++vs->vs_control_refs > default_pager_max_urefs) {
        !           387:                delta = 1 - vs->vs_control_refs;
        !           388:                vs->vs_control_refs = 1;
        !           389: 
        !           390:                VS_UNLOCK(vs);
        !           391: 
        !           392:                /*
        !           393:                 * Deallocate excess user references.
        !           394:                 */
        !           395: 
        !           396:                {
        !           397: /* find a better interface for this, what will we use as a component */
        !           398:                        int i;
        !           399:                        delta = -delta;
        !           400:                        for(i=0; i<delta; i++)
        !           401:                                ipc_port_release_send(control_port);
        !           402:                }
        !           403: 
        !           404:                VS_LOCK(vs);
        !           405:        }
        !           406: }
        !           407: 
        !           408: void default_pager_add(vstruct_t, boolean_t);  /* forward */
        !           409: 
        !           410: void
        !           411: default_pager_add(
        !           412:        vstruct_t vs,
        !           413:        boolean_t internal)
        !           414: {
        !           415:        MACH_PORT_FACE          mem_obj = vs->vs_mem_obj_port;
        !           416:        MACH_PORT_FACE          pset;
        !           417:        mach_port_mscount_t     sync;
        !           418:        MACH_PORT_FACE          previous;
        !           419:        kern_return_t           kr;
        !           420:        static char             here[] = "default_pager_add";
        !           421: 
        !           422:        /*
        !           423:         * The port currently has a make-send count of zero,
        !           424:         * because either we just created the port or we just
        !           425:         * received the port in a memory_object_create request.
        !           426:         */
        !           427: 
        !           428:        if (internal) {
        !           429:                /* possibly generate an immediate no-senders notification */
        !           430:                sync = 0;
        !           431:                pset = default_pager_internal_set;
        !           432:        } else {
        !           433:                /* delay notification till send right is created */
        !           434:                sync = 1;
        !           435:                pset = default_pager_external_set;
        !           436:        }
        !           437: 
        !           438:        ipc_port_make_sonce(mem_obj);
        !           439:        ip_lock(mem_obj);  /* unlocked in nsrequest below */
        !           440:        ipc_port_nsrequest(mem_obj, sync, mem_obj, &previous);
        !           441: }
        !           442: 
        !           443: 
        !           444: /*
        !           445:  * Routine:    dp_memory_object_create
        !           446:  * Purpose:
        !           447:  *     Handle requests for memory objects from the
        !           448:  *     kernel.
        !           449:  * Notes:
        !           450:  *     Because we only give out the default memory
        !           451:  *     manager port to the kernel, we don't have to
        !           452:  *     be so paranoid about the contents.
        !           453:  */
        !           454: kern_return_t
        !           455: dp_memory_object_create(
        !           456:        MACH_PORT_FACE          dmm,
        !           457:        MACH_PORT_FACE          *new_mem_obj,
        !           458:        vm_size_t               new_size)
        !           459: {
        !           460:        mach_port_seqno_t       seqno;
        !           461:        vstruct_t               vs;
        !           462:        MACH_PORT_FACE          pager;
        !           463:        static char             here[] = "memory_object_create";
        !           464: 
        !           465:        assert(dmm == default_pager_default_port);
        !           466: 
        !           467:        vs = vs_object_create(new_size);
        !           468:        if (vs == VSTRUCT_NULL)
        !           469:                return KERN_RESOURCE_SHORTAGE;
        !           470: 
        !           471:        pager = *new_mem_obj = ipc_port_alloc_kernel();
        !           472:        assert (pager != IP_NULL);
        !           473:        (void) ipc_port_make_send(pager);
        !           474: 
        !           475:        {
        !           476:           struct vstruct_alias *alias_struct;
        !           477: 
        !           478:           alias_struct = (struct vstruct_alias *)
        !           479:                        kalloc(sizeof(struct vstruct_alias));
        !           480:           if(alias_struct != NULL) {
        !           481:                alias_struct->vs = vs;
        !           482:                alias_struct->name = ISVS;
        !           483:                pager->alias = (int) alias_struct;
        !           484:           }
        !           485:           else Panic("Out of kernel memory");
        !           486: 
        !           487:           /* JMM - Add binding to this pager under components */
        !           488:           pager_mux_hash_insert(pager, &dp_memory_object_subsystem);
        !           489:           vs->vs_next_seqno = 0;
        !           490:           pager->ip_receiver = ipc_space_kernel;
        !           491:        }
        !           492: 
        !           493:        /*
        !           494:         * Set up associations between this port
        !           495:         * and this default_pager structure
        !           496:         */
        !           497: 
        !           498:        vs->vs_mem_obj_port = pager;
        !           499: 
        !           500:        /*
        !           501:         * After this, other threads might receive requests
        !           502:         * for this memory object or find it in the port list.
        !           503:         */
        !           504: 
        !           505:        vstruct_list_insert(vs);
        !           506:        default_pager_add(vs, TRUE);
        !           507: 
        !           508:        return KERN_SUCCESS;
        !           509: }
        !           510: 
        !           511: kern_return_t
        !           512: dp_memory_object_init(
        !           513:        MACH_PORT_FACE          mem_obj,
        !           514:        MACH_PORT_FACE          control_port,
        !           515:        vm_size_t               pager_page_size)
        !           516: {
        !           517:        mach_port_seqno_t       seqno;
        !           518:        vstruct_t               vs;
        !           519:        static char             here[] = "memory_object_init";
        !           520: 
        !           521:        assert(pager_page_size == vm_page_size);
        !           522: 
        !           523:        vs_lookup(mem_obj, vs);
        !           524:        vs_lock(vs, seqno);
        !           525: 
        !           526:        if (vs->vs_control_port != MACH_PORT_NULL)
        !           527:                Panic("bad request");
        !           528: 
        !           529:        vs->vs_control_port = control_port;
        !           530:        vs->vs_control_refs = 1;
        !           531:        vs->vs_object_name = MACH_PORT_NULL;
        !           532:        vs->vs_name_refs = 1;
        !           533: 
        !           534:        vs_unlock(vs);
        !           535: 
        !           536:        return KERN_SUCCESS;
        !           537: }
        !           538: 
        !           539: kern_return_t
        !           540: dp_memory_object_synchronize(
        !           541:        MACH_PORT_FACE          mem_obj,
        !           542:        MACH_PORT_FACE          control_port,
        !           543:        vm_offset_t             offset,
        !           544:        vm_offset_t             length,
        !           545:        vm_sync_t               flags)
        !           546: {
        !           547:        mach_port_seqno_t       seqno;
        !           548:        vstruct_t       vs;
        !           549:        static char     here[] = "memory_object_synchronize";
        !           550: 
        !           551:        vs_lookup(mem_obj, vs);
        !           552:        vs_lock(vs, seqno);
        !           553:        vs_check_request(vs, control_port);
        !           554:        vs_unlock(vs);
        !           555: 
        !           556:        memory_object_synchronize_completed(
        !           557:                                vm_object_lookup(control_port), 
        !           558:                                offset, length);
        !           559: 
        !           560:        return KERN_SUCCESS;
        !           561: }
        !           562: 
        !           563: kern_return_t
        !           564: dp_memory_object_terminate(
        !           565:        MACH_PORT_FACE          mem_obj,
        !           566:        MACH_PORT_FACE          control_port)
        !           567: {
        !           568:        mach_port_seqno_t       seqno;
        !           569:        vstruct_t               vs;
        !           570:        mach_port_urefs_t       request_refs;
        !           571:        kern_return_t           kr;
        !           572:        static char             here[] = "memory_object_terminate";
        !           573: 
        !           574:        /* 
        !           575:         * control port is a receive right, not a send right.
        !           576:         */
        !           577: 
        !           578:        vs_lookup(mem_obj, vs);
        !           579:        vs_lock(vs, seqno);
        !           580: 
        !           581:        /*
        !           582:         * Wait for read and write requests to terminate.
        !           583:         */
        !           584: 
        !           585:        vs_wait_for_readers(vs);
        !           586:        vs_wait_for_writers(vs);
        !           587: 
        !           588:        /*
        !           589:         * After memory_object_terminate both memory_object_init
        !           590:         * and a no-senders notification are possible, so we need
        !           591:         * to clean up the request and name ports but leave
        !           592:         * the mem_obj port.
        !           593:         *
        !           594:         * A concurrent default_pager_objects might be allocating
        !           595:         * more references for the name port.  In this case,
        !           596:         * we must first wait for it to finish.
        !           597:         */
        !           598: 
        !           599:        vs_wait_for_refs(vs);
        !           600: 
        !           601:        vs->vs_control_port = MACH_PORT_NULL;
        !           602: 
        !           603:        /* a bit of special case ugliness here.  Wakeup any waiting reads */
        !           604:        /* these data requests had to be removed from the seqno traffic   */
        !           605:        /* based on a performance bottleneck with large memory objects    */
        !           606:        /* the problem will right itself with the new component based     */
        !           607:        /* synchronous interface.  The new async will be able to return   */
        !           608:        /* failure during its sync phase.   In the mean time ... */
        !           609: 
        !           610:                thread_wakeup(&vs->vs_waiting_write);
        !           611:                thread_wakeup(&vs->vs_waiting_async);
        !           612: 
        !           613:        request_refs = vs->vs_control_refs;
        !           614:        vs->vs_control_refs = 0;
        !           615: 
        !           616:        vs->vs_object_name = MACH_PORT_NULL;
        !           617: 
        !           618:        assert(vs->vs_name_refs != 0);
        !           619:        vs->vs_name_refs = 0;
        !           620: 
        !           621:        vs_unlock(vs);
        !           622: 
        !           623:        /*
        !           624:         * Now we deallocate our various port rights.
        !           625:         */
        !           626: 
        !           627:        {
        !           628:                int i;
        !           629:                for(i=0; i<request_refs; i++)
        !           630:                        ipc_port_release_send(control_port);
        !           631:        }
        !           632:         if(control_port->alias != (int)NULL) 
        !           633:                 kfree((vm_offset_t) (control_port->alias), 
        !           634:                                        sizeof(struct vstruct_alias));
        !           635:        ipc_port_release_receive(control_port);
        !           636:        return KERN_SUCCESS;
        !           637: }
        !           638: 
        !           639: void
        !           640: default_pager_no_senders(
        !           641:        MACH_PORT_FACE          mem_obj,
        !           642:        mach_port_seqno_t       seqno,
        !           643:        mach_port_mscount_t     mscount)
        !           644: {
        !           645:        vstruct_t               vs;
        !           646:        static char             here[] = "default_pager_no_senders";
        !           647: 
        !           648:        /*
        !           649:         * Because we don't give out multiple send rights
        !           650:         * for a memory object, there can't be a race
        !           651:         * between getting a no-senders notification
        !           652:         * and creating a new send right for the object.
        !           653:         * Hence we don't keep track of mscount.
        !           654:         */
        !           655: 
        !           656:        vs_lookup(mem_obj, vs);
        !           657:        vs_lock(vs, seqno);
        !           658:        vs_async_wait(vs);      /* wait for pending async IO */
        !           659: 
        !           660:        /* do not delete the vs structure until the referencing pointers */
        !           661:        /* in the vstruct list have been expunged */
        !           662: 
        !           663:        /* get VSL_LOCK out of order by using TRY mechanism */
        !           664:        while(!VSL_LOCK_TRY()) {
        !           665:                VS_UNLOCK(vs);
        !           666:                VSL_LOCK();
        !           667:                VSL_UNLOCK();
        !           668:                VS_LOCK(vs);
        !           669:                vs_async_wait(vs);      /* wait for pending async IO */
        !           670:        }
        !           671:        /*
        !           672:         * We shouldn't get a no-senders notification
        !           673:         * when the kernel has the object cached.
        !           674:         */
        !           675:        if (vs->vs_control_port != MACH_PORT_NULL)
        !           676:                Panic("bad request");
        !           677: 
        !           678:        /*
        !           679:         * Unlock the pager (though there should be no one
        !           680:         * waiting for it).
        !           681:         */
        !           682:        VS_UNLOCK(vs);
        !           683: 
        !           684:        /*
        !           685:         * Remove the memory object port association, and then
        !           686:         * the destroy the port itself.  We must remove the object
        !           687:         * from the port list before deallocating the pager,
        !           688:         * because of default_pager_objects.
        !           689:         */
        !           690:        vstruct_list_delete(vs);
        !           691:        ps_vstruct_dealloc(vs);
        !           692: 
        !           693:        /*
        !           694:         * Recover memory that we might have wasted because
        !           695:         * of name conflicts
        !           696:         */
        !           697:        while (!queue_empty(&vstruct_list.vsl_leak_queue)) {
        !           698:                vs = (vstruct_t) queue_first(&vstruct_list.vsl_leak_queue);
        !           699:                queue_remove_first(&vstruct_list.vsl_leak_queue, vs, vstruct_t,
        !           700:                                   vs_links);
        !           701:                kfree((vm_offset_t) vs, sizeof *vs);
        !           702:        }
        !           703:        VSL_UNLOCK();
        !           704: }
        !           705: 
        !           706: kern_return_t
        !           707: dp_memory_object_data_request(
        !           708:        MACH_PORT_FACE          mem_obj,
        !           709:        MACH_PORT_FACE          reply_to,
        !           710:        vm_offset_t             offset,
        !           711:        vm_size_t               length,
        !           712:        vm_prot_t               protection_required)
        !           713: {
        !           714:        mach_port_seqno_t       seqno;
        !           715:        vstruct_t               vs;
        !           716:        static char             here[] = "memory_object_data_request";
        !           717: 
        !           718:        GSTAT(global_stats.gs_pagein_calls++);
        !           719: 
        !           720: 
        !           721:        /* CDY at this moment vs_lookup panics when presented with the wrong */
        !           722:        /* port.  As we are expanding this pager to support user interfaces */
        !           723:        /* this should be changed to return kern_failure */
        !           724:        vs_lookup(mem_obj, vs);
        !           725:        vs_lock(vs, seqno);
        !           726:        vs_check_request(vs, reply_to);
        !           727: 
        !           728:        /* We are going to relax the strict sequencing here for performance */
        !           729:        /* reasons.  We can do this because we know that the read and */
        !           730:        /* write threads are different and we rely on synchronization */
        !           731:        /* of read and write requests at the cache memory_object level */
        !           732:        /* break out wait_for_writers, all of this goes away when */
        !           733:        /* we get real control of seqno with the new component interface */
        !           734:        if (vs->vs_writers != 0) {
        !           735:                /* you can't hold on to the seqno and go */
        !           736:                /* to sleep like that */
        !           737:                vs_unlock(vs);  /* bump internal count of seqno */
        !           738:                VS_LOCK(vs);
        !           739:                while (vs->vs_writers != 0) {
        !           740:                        default_pager_wait_write++;
        !           741:                        vs->vs_waiting_write = TRUE;
        !           742:                        assert_wait(&vs->vs_waiting_write, THREAD_UNINT);
        !           743:                        VS_UNLOCK(vs);
        !           744:                        thread_block((void (*)(void))0);
        !           745:                        VS_LOCK(vs);
        !           746:                        vs_async_wait(vs);
        !           747:                }
        !           748:                if(vs->vs_control_port == MACH_PORT_NULL) {
        !           749:                        VS_UNLOCK(vs);
        !           750:                        return KERN_FAILURE;
        !           751:                }
        !           752:                vs_start_read(vs);
        !           753:                VS_UNLOCK(vs);
        !           754:        } else {
        !           755:                vs_start_read(vs);
        !           756:                vs_unlock(vs);
        !           757:        }
        !           758: 
        !           759:        /*
        !           760:         * Request must be on a page boundary and a multiple of pages.
        !           761:         */
        !           762:        if ((offset & vm_page_mask) != 0 || (length & vm_page_mask) != 0)
        !           763:                Panic("bad alignment");
        !           764: 
        !           765:        pvs_cluster_read(vs, offset, length);
        !           766: 
        !           767:        vs_finish_read(vs);
        !           768: 
        !           769:        return KERN_SUCCESS;
        !           770: }
        !           771: 
        !           772: /*
        !           773:  * memory_object_data_initialize: check whether we already have each page, and
        !           774:  * write it if we do not.  The implementation is far from optimized, and
        !           775:  * also assumes that the default_pager is single-threaded.
        !           776:  */
        !           777: /*  It is questionable whether or not a pager should decide what is relevant */
        !           778: /* and what is not in data sent from the kernel.  Data initialize has been */
        !           779: /* changed to copy back all data sent to it in preparation for its eventual */
        !           780: /* merge with data return.  It is the kernel that should decide what pages */
        !           781: /* to write back.  As of the writing of this note, this is indeed the case */
        !           782: /* the kernel writes back one page at a time through this interface */
        !           783: 
        !           784: kern_return_t
        !           785: dp_memory_object_data_initialize(
        !           786:        MACH_PORT_FACE          mem_obj,
        !           787:        MACH_PORT_FACE          control_port,
        !           788:        vm_offset_t             offset,
        !           789:        pointer_t               addr,
        !           790:        vm_size_t               data_cnt)
        !           791: {
        !           792:        mach_port_seqno_t       seqno;
        !           793:        vstruct_t       vs;
        !           794:        static char     here[] = "memory_object_data_initialize";
        !           795: 
        !           796: #ifdef lint
        !           797:        control_port++;
        !           798: #endif /* lint */
        !           799: 
        !           800:        DEBUG(DEBUG_MO_EXTERNAL,
        !           801:              ("mem_obj=0x%x,offset=0x%x,cnt=0x%x\n",
        !           802:               (int)mem_obj, (int)offset, (int)data_cnt));
        !           803:        GSTAT(global_stats.gs_pages_init += atop(data_cnt));
        !           804: 
        !           805:        vs_lookup(mem_obj, vs);
        !           806:        vs_lock(vs, seqno);
        !           807:        vs_check_request(vs, control_port);
        !           808:        vs_start_write(vs);
        !           809:        vs_unlock(vs);
        !           810: 
        !           811:        /*
        !           812:         * Write the data via clustered writes. vs_cluster_write will
        !           813:         * loop if the address range specified crosses cluster
        !           814:         * boundaries.
        !           815:         */
        !           816:        vs_cluster_write(vs, offset, addr, data_cnt, FALSE);
        !           817: 
        !           818:        vs_finish_write(vs);
        !           819: 
        !           820:        return KERN_SUCCESS;
        !           821: }
        !           822: 
        !           823: kern_return_t
        !           824: dp_memory_object_lock_completed(
        !           825:        memory_object_t         mem_obj,
        !           826:        MACH_PORT_FACE          control_port,
        !           827:        vm_offset_t             offset,
        !           828:        vm_size_t               length)
        !           829: {
        !           830:        mach_port_seqno_t       seqno;
        !           831:        static char     here[] = "memory_object_lock_completed";
        !           832: 
        !           833: #ifdef lint
        !           834:        mem_obj++; 
        !           835:        seqno++; 
        !           836:        control_port++; 
        !           837:        offset++; 
        !           838:        length++;
        !           839: #endif /* lint */
        !           840: 
        !           841:        Panic("illegal");
        !           842:        return KERN_FAILURE;
        !           843: }
        !           844: 
        !           845: kern_return_t
        !           846: dp_memory_object_data_unlock(
        !           847:        memory_object_t         mem_obj,
        !           848:        MACH_PORT_FACE          control_port,
        !           849:        vm_offset_t             offset,
        !           850:        vm_size_t               data_cnt,
        !           851:        vm_prot_t               desired_access)
        !           852: {
        !           853:        static char     here[] = "memory_object_data_unlock";
        !           854: 
        !           855:        Panic("illegal");
        !           856:        return KERN_FAILURE;
        !           857: }
        !           858: 
        !           859: 
        !           860: kern_return_t
        !           861: dp_memory_object_supply_completed(
        !           862:        memory_object_t         mem_obj,
        !           863:        MACH_PORT_FACE          control_port,
        !           864:        vm_offset_t             offset,
        !           865:        vm_size_t               length,
        !           866:        kern_return_t           result,
        !           867:        vm_offset_t             error_offset)
        !           868: {
        !           869:        static char     here[] = "memory_object_supply_completed";
        !           870: 
        !           871:        Panic("illegal");
        !           872:        return KERN_FAILURE;
        !           873: }
        !           874: 
        !           875: kern_return_t
        !           876: dp_memory_object_data_return(
        !           877:        MACH_PORT_FACE          mem_obj,
        !           878:        MACH_PORT_FACE          control_port,
        !           879:        vm_offset_t             offset,
        !           880:        pointer_t               addr,
        !           881:        vm_size_t               data_cnt,
        !           882:        boolean_t               dirty,
        !           883:        boolean_t               kernel_copy)
        !           884: {
        !           885:        mach_port_seqno_t       seqno;
        !           886:        vstruct_t       vs;
        !           887:        vm_offset_t     pageout_address;
        !           888:        static char     here[] = "memory_object_data_return";
        !           889: 
        !           890: #ifdef lint
        !           891:        control_port++;
        !           892:        dirty++;
        !           893:        kernel_copy++;
        !           894: #endif /* lint */
        !           895: 
        !           896:        DEBUG(DEBUG_MO_EXTERNAL,
        !           897:              ("mem_obj=0x%x,offset=0x%x,addr=0x%xcnt=0x%x\n",
        !           898:               (int)mem_obj, (int)offset, (int)addr, (int)data_cnt));
        !           899:        GSTAT(global_stats.gs_pageout_calls++);
        !           900: 
        !           901:        /* This routine is called by the pageout thread.  The pageout thread */
        !           902:        /* cannot be blocked by read activities unless the read activities   */
        !           903:        /* Therefore the grant of vs lock must be done on a try versus a      */
        !           904:        /* blocking basis.  The code below relies on the fact that the       */
        !           905:        /* interface is synchronous.  Should this interface be again async   */
        !           906:        /* for some type  of pager in the future the pages will have to be   */
        !           907:        /* returned through a separate, asynchronous path.                   */
        !           908: 
        !           909:        vs_lookup(mem_obj, vs);
        !           910: 
        !           911:         default_pager_total++;
        !           912:        if(!VS_TRY_LOCK(vs)) {
        !           913:                /* the call below will not be done by caller when we have */
        !           914:                /* a synchronous interface */
        !           915:                /* return KERN_LOCK_OWNED; */
        !           916:                upl_t           page_list;
        !           917:                upl_system_list_request((vm_object_t)
        !           918:                                 vs->vs_control_port->ip_kobject,
        !           919:                                 offset, data_cnt, data_cnt, &page_list, NULL, 0,
        !           920:                                        UPL_NOBLOCK | UPL_CLEAN_IN_PLACE | 
        !           921:                                                UPL_NO_SYNC | UPL_COPYOUT_FROM);
        !           922: 
        !           923:                upl_abort(page_list,0);
        !           924:                return KERN_SUCCESS;
        !           925:        }
        !           926: 
        !           927: 
        !           928: 
        !           929:        if ((vs->vs_seqno != vs->vs_next_seqno++) || (vs->vs_xfer_pending)) {
        !           930:                upl_t   page_list;
        !           931:                vs->vs_next_seqno--;
        !           932:                 VS_UNLOCK(vs);
        !           933:                /* the call below will not be done by caller when we have */
        !           934:                /* a synchronous interface */
        !           935:                /* return KERN_LOCK_OWNED; */
        !           936:                upl_system_list_request((vm_object_t)
        !           937:                                 vs->vs_control_port->ip_kobject,
        !           938:                                 offset, data_cnt, data_cnt, &page_list, NULL, 0,
        !           939:                                        UPL_NOBLOCK | UPL_CLEAN_IN_PLACE | 
        !           940:                                                UPL_NO_SYNC | UPL_COPYOUT_FROM);
        !           941:                upl_abort(page_list,0);
        !           942:                return KERN_SUCCESS;
        !           943:        }
        !           944: 
        !           945:        if ((data_cnt % vm_page_size) != 0)
        !           946:                Panic("bad alignment");
        !           947: 
        !           948: /*
        !           949:        vs_check_request(vs, control_port);
        !           950: */
        !           951:        vs_start_write(vs);
        !           952:        vs_unlock(vs);
        !           953: 
        !           954:        /*
        !           955:         * Write the data via clustered writes. vs_cluster_write will
        !           956:         * loop if the address range specified crosses cluster
        !           957:         * boundaries.
        !           958:         */
        !           959:        vs_cluster_write(vs, offset, addr, data_cnt, FALSE);
        !           960: 
        !           961:        vs_finish_write(vs);
        !           962: 
        !           963:        return KERN_SUCCESS;
        !           964: }
        !           965: 
        !           966: kern_return_t
        !           967: dp_memory_object_discard_request(
        !           968:        memory_object_t         mem_obj, 
        !           969:        memory_object_control_t memory_control,
        !           970:        vm_offset_t             offset, 
        !           971:        vm_size_t               length)
        !           972: {
        !           973:        panic("illegal");
        !           974:        return KERN_FAILURE;
        !           975: }
        !           976: 
        !           977: kern_return_t
        !           978: dp_memory_object_change_completed(
        !           979:        memory_object_t         mem_obj,
        !           980:        memory_object_control_t memory_control,
        !           981:        memory_object_flavor_t  flavor)
        !           982: {
        !           983:        static char     here[] = "memory_object_change_completed";
        !           984: 
        !           985:        Panic("illegal");
        !           986:        return KERN_FAILURE;
        !           987: }
        !           988: 
        !           989: /*
        !           990:  * Create an external object.
        !           991:  */
        !           992: kern_return_t
        !           993: default_pager_object_create(
        !           994:        MACH_PORT_FACE  pager,
        !           995:        MACH_PORT_FACE  *mem_obj,
        !           996:        vm_size_t       size)
        !           997: {
        !           998:        vstruct_t       vs;
        !           999:        MACH_PORT_FACE  port;
        !          1000:        kern_return_t   result;
        !          1001:        struct vstruct_alias    *alias_struct;
        !          1002:        static char     here[] = "default_pager_object_create";
        !          1003: 
        !          1004: 
        !          1005:        if (pager != default_pager_default_port)
        !          1006:                return KERN_INVALID_ARGUMENT;
        !          1007: 
        !          1008:        vs = vs_object_create(size);
        !          1009: 
        !          1010:        port = ipc_port_alloc_kernel();
        !          1011:        ipc_port_make_send(port);
        !          1012:        /* register abstract memory object port with pager mux routine */
        !          1013:        /* (directs kernel internal calls to the right pager). */
        !          1014:        alias_struct = (struct vstruct_alias *)
        !          1015:                        kalloc(sizeof(struct vstruct_alias));
        !          1016:        if(alias_struct != NULL) {
        !          1017:                alias_struct->vs = vs;
        !          1018:                alias_struct->name = ISVS;
        !          1019:                port->alias = (int) alias_struct;
        !          1020:        }
        !          1021:        else Panic("Out of kernel memory");
        !          1022:                
        !          1023:        /*
        !          1024:         * Set up associations between these ports
        !          1025:         * and this vstruct structure
        !          1026:         */
        !          1027: 
        !          1028:        vs->vs_mem_obj_port = port;
        !          1029:        vstruct_list_insert(vs);
        !          1030:        default_pager_add(vs, FALSE);
        !          1031: 
        !          1032:        *mem_obj = port;
        !          1033: 
        !          1034:        return KERN_SUCCESS;
        !          1035: }
        !          1036: 
        !          1037: kern_return_t
        !          1038: default_pager_objects(
        !          1039:        MACH_PORT_FACE                  pager,
        !          1040:        default_pager_object_array_t    *objectsp,
        !          1041:        mach_msg_type_number_t          *ocountp,
        !          1042:        mach_port_array_t               *portsp,
        !          1043:        mach_msg_type_number_t          *pcountp)
        !          1044: {
        !          1045:        vm_offset_t             oaddr = 0;      /* memory for objects */
        !          1046:        vm_size_t               osize = 0;      /* current size */
        !          1047:        default_pager_object_t  * objects;
        !          1048:        unsigned int            opotential;
        !          1049: 
        !          1050:        vm_offset_t             paddr = 0;      /* memory for ports */
        !          1051:        vm_size_t               psize = 0;      /* current size */
        !          1052:        MACH_PORT_FACE           * ports;
        !          1053:        unsigned int            ppotential;
        !          1054: 
        !          1055:        unsigned int            actual;
        !          1056:        unsigned int            num_objects;
        !          1057:        kern_return_t           kr;
        !          1058:        vstruct_t               entry;
        !          1059:        static char             here[] = "default_pager_objects";
        !          1060: /*
        !          1061:        if (pager != default_pager_default_port)
        !          1062:                return KERN_INVALID_ARGUMENT;
        !          1063: */
        !          1064: 
        !          1065:        /* start with the inline memory */
        !          1066: 
        !          1067:        kr = vm_map_copyout(ipc_kernel_map, (vm_offset_t *)&objects, 
        !          1068:                                                (vm_map_copy_t) *objectsp);
        !          1069: 
        !          1070:        if (kr != KERN_SUCCESS)
        !          1071:                return kr;
        !          1072: 
        !          1073:        osize = round_page(*ocountp * sizeof * objects);
        !          1074:        kr = vm_map_wire(ipc_kernel_map, 
        !          1075:                        trunc_page((vm_offset_t)objects),
        !          1076:                        round_page(((vm_offset_t)objects) + osize), 
        !          1077:                        VM_PROT_READ|VM_PROT_WRITE, FALSE);
        !          1078:        osize=0;
        !          1079: 
        !          1080:        *objectsp = objects;
        !          1081:        /* we start with the inline space */
        !          1082: 
        !          1083: 
        !          1084:        num_objects = 0;
        !          1085:        opotential = *ocountp;
        !          1086: 
        !          1087:        ports = (MACH_PORT_FACE *) *portsp;
        !          1088:        ppotential = *pcountp;
        !          1089: 
        !          1090:        VSL_LOCK();
        !          1091: 
        !          1092:        /*
        !          1093:         * We will send no more than this many
        !          1094:         */
        !          1095:        actual = vstruct_list.vsl_count;
        !          1096:        VSL_UNLOCK();
        !          1097: 
        !          1098:        if (opotential < actual) {
        !          1099:                vm_offset_t     newaddr;
        !          1100:                vm_size_t       newsize;
        !          1101: 
        !          1102:                newsize = 2 * round_page(actual * sizeof * objects);
        !          1103: 
        !          1104:                kr = vm_allocate(kernel_map, &newaddr, newsize, TRUE);
        !          1105:                if (kr != KERN_SUCCESS)
        !          1106:                        goto nomemory;
        !          1107: 
        !          1108:                oaddr = newaddr;
        !          1109:                osize = newsize;
        !          1110:                opotential = osize / sizeof * objects;
        !          1111:                objects = (default_pager_object_t *)oaddr;
        !          1112:        }
        !          1113: 
        !          1114:        if (ppotential < actual) {
        !          1115:                vm_offset_t     newaddr;
        !          1116:                vm_size_t       newsize;
        !          1117: 
        !          1118:                newsize = 2 * round_page(actual * sizeof * ports);
        !          1119: 
        !          1120:                kr = vm_allocate(kernel_map, &newaddr, newsize, TRUE);
        !          1121:                if (kr != KERN_SUCCESS)
        !          1122:                        goto nomemory;
        !          1123: 
        !          1124:                paddr = newaddr;
        !          1125:                psize = newsize;
        !          1126:                ppotential = psize / sizeof * ports;
        !          1127:                ports = (MACH_PORT_FACE *)paddr;
        !          1128:        }
        !          1129: 
        !          1130:        /*
        !          1131:         * Now scan the list.
        !          1132:         */
        !          1133: 
        !          1134:        VSL_LOCK();
        !          1135: 
        !          1136:        num_objects = 0;
        !          1137:        queue_iterate(&vstruct_list.vsl_queue, entry, vstruct_t, vs_links) {
        !          1138: 
        !          1139:                MACH_PORT_FACE          port;
        !          1140:                vm_size_t               size;
        !          1141: 
        !          1142:                if ((num_objects >= opotential) ||
        !          1143:                    (num_objects >= ppotential)) {
        !          1144: 
        !          1145:                        /*
        !          1146:                         * This should be rare.  In any case,
        !          1147:                         * we will only miss recent objects,
        !          1148:                         * because they are added at the end.
        !          1149:                         */
        !          1150:                        break;
        !          1151:                }
        !          1152: 
        !          1153:                /*
        !          1154:                 * Avoid interfering with normal operations
        !          1155:                 */
        !          1156:                if (!VS_MAP_TRY_LOCK(entry))
        !          1157:                        goto not_this_one;
        !          1158:                size = ps_vstruct_allocated_size(entry);
        !          1159:                VS_MAP_UNLOCK(entry);
        !          1160: 
        !          1161:                VS_LOCK(entry);
        !          1162: 
        !          1163:                port = entry->vs_object_name;
        !          1164:                if (port == MACH_PORT_NULL) {
        !          1165: 
        !          1166:                        /*
        !          1167:                         * The object is waiting for no-senders
        !          1168:                         * or memory_object_init.
        !          1169:                         */
        !          1170:                        VS_UNLOCK(entry);
        !          1171:                        goto not_this_one;
        !          1172:                }
        !          1173: 
        !          1174:                /*
        !          1175:                 * We need a reference for the reply message.
        !          1176:                 * While we are unlocked, the bucket queue
        !          1177:                 * can change and the object might be terminated.
        !          1178:                 * memory_object_terminate will wait for us,
        !          1179:                 * preventing deallocation of the entry.
        !          1180:                 */
        !          1181: 
        !          1182:                if (--entry->vs_name_refs == 0) {
        !          1183:                        VS_UNLOCK(entry);
        !          1184: 
        !          1185:                        /* keep the list locked, wont take long */
        !          1186: 
        !          1187:                        {
        !          1188:                                int i;
        !          1189:                                for(i=0; i<default_pager_max_urefs; i++)
        !          1190:                                        ipc_port_make_send(port);
        !          1191:                        }
        !          1192:                        VS_LOCK(entry);
        !          1193: 
        !          1194:                        entry->vs_name_refs += default_pager_max_urefs;
        !          1195:                        vs_finish_refs(entry);
        !          1196:                }
        !          1197:                VS_UNLOCK(entry);
        !          1198: 
        !          1199:                /* the arrays are wired, so no deadlock worries */
        !          1200: 
        !          1201:                objects[num_objects].dpo_object = (vm_offset_t) entry;
        !          1202:                objects[num_objects].dpo_size = size;
        !          1203:                ports  [num_objects++] = port;
        !          1204:                continue;
        !          1205: 
        !          1206:            not_this_one:
        !          1207:                /*
        !          1208:                 * Do not return garbage
        !          1209:                 */
        !          1210:                objects[num_objects].dpo_object = (vm_offset_t) 0;
        !          1211:                objects[num_objects].dpo_size = 0;
        !          1212:                ports  [num_objects++] = MACH_PORT_NULL;
        !          1213: 
        !          1214:        }
        !          1215: 
        !          1216:        VSL_UNLOCK();
        !          1217: 
        !          1218:        /*
        !          1219:         * Deallocate and clear unused memory.
        !          1220:         * (Returned memory will automagically become pageable.)
        !          1221:         */
        !          1222: 
        !          1223:        if (objects == *objectsp) {
        !          1224: 
        !          1225:                /*
        !          1226:                 * Our returned information fit inline.
        !          1227:                 * Nothing to deallocate.
        !          1228:                 */
        !          1229:                *ocountp = num_objects;
        !          1230:        } else if (actual == 0) {
        !          1231:                (void) vm_deallocate(kernel_map, oaddr, osize);
        !          1232: 
        !          1233:                /* return zero items inline */
        !          1234:                *ocountp = 0;
        !          1235:        } else {
        !          1236:                vm_offset_t used;
        !          1237: 
        !          1238:                used = round_page(actual * sizeof * objects);
        !          1239: 
        !          1240:                if (used != osize)
        !          1241:                        (void) vm_deallocate(kernel_map,
        !          1242:                                             oaddr + used, osize - used);
        !          1243: 
        !          1244:                *objectsp = objects;
        !          1245:                *ocountp = num_objects;
        !          1246:        }
        !          1247: 
        !          1248:        if (ports == (MACH_PORT_FACE *)*portsp) {
        !          1249: 
        !          1250:                /*
        !          1251:                 * Our returned information fit inline.
        !          1252:                 * Nothing to deallocate.
        !          1253:                 */
        !          1254: 
        !          1255:                *pcountp = num_objects;
        !          1256:        } else if (actual == 0) {
        !          1257:                (void) vm_deallocate(kernel_map, paddr, psize);
        !          1258: 
        !          1259:                /* return zero items inline */
        !          1260:                *pcountp = 0;
        !          1261:        } else {
        !          1262:                vm_offset_t used;
        !          1263: 
        !          1264:                used = round_page(actual * sizeof * ports);
        !          1265: 
        !          1266:                if (used != psize)
        !          1267:                        (void) vm_deallocate(kernel_map,
        !          1268:                                             paddr + used, psize - used);
        !          1269: 
        !          1270:                *portsp = (mach_port_array_t)ports;
        !          1271:                *pcountp = num_objects;
        !          1272:        }
        !          1273:        (void) vm_map_unwire(kernel_map, (vm_offset_t)objects, 
        !          1274:                        *ocountp + (vm_offset_t)objects, FALSE); 
        !          1275:        (void) vm_map_copyin(kernel_map, (vm_offset_t)objects, 
        !          1276:                        *ocountp, TRUE, (vm_map_copy_t *)objectsp);
        !          1277: 
        !          1278:        return KERN_SUCCESS;
        !          1279: 
        !          1280:     nomemory:
        !          1281:        {
        !          1282:                register int    i;
        !          1283:                for (i = 0; i < num_objects; i++)
        !          1284:                        ipc_port_dealloc_kernel(ports[i]);
        !          1285:        }
        !          1286: 
        !          1287:        if (objects != *objectsp)
        !          1288:                (void) vm_deallocate(kernel_map, oaddr, osize);
        !          1289: 
        !          1290:        if (ports != (MACH_PORT_FACE *)*portsp)
        !          1291:                (void) vm_deallocate(kernel_map, paddr, psize);
        !          1292: 
        !          1293:        return KERN_RESOURCE_SHORTAGE;
        !          1294: }
        !          1295: 
        !          1296: kern_return_t
        !          1297: default_pager_object_pages(
        !          1298:        MACH_PORT_FACE                  pager,
        !          1299:        MACH_PORT_FACE                  object,
        !          1300:        default_pager_page_array_t      *pagesp,
        !          1301:        mach_msg_type_number_t          *countp)
        !          1302: {
        !          1303:        vm_offset_t                     addr;   /* memory for page offsets */
        !          1304:        vm_size_t                       size = 0; /* current memory size */
        !          1305:        default_pager_page_t            * pages;
        !          1306:        unsigned int                    potential, actual;
        !          1307:        kern_return_t                   kr;
        !          1308: 
        !          1309: /*
        !          1310:        if (pager != default_pager_default_port)
        !          1311:                return KERN_INVALID_ARGUMENT;
        !          1312: */
        !          1313:        kr = vm_map_copyout(ipc_kernel_map, (vm_offset_t *)&pages, 
        !          1314:                                                (vm_map_copy_t) *pagesp);
        !          1315: 
        !          1316:        if (kr != KERN_SUCCESS)
        !          1317:                return kr;
        !          1318: 
        !          1319:        size = round_page(*countp * sizeof * pages);
        !          1320:        kr = vm_map_wire(ipc_kernel_map, 
        !          1321:                        trunc_page((vm_offset_t)pages),
        !          1322:                        round_page(((vm_offset_t)pages) + size), 
        !          1323:                        VM_PROT_READ|VM_PROT_WRITE, FALSE);
        !          1324:        size=0;
        !          1325: 
        !          1326:        *pagesp = pages;
        !          1327:        /* we start with the inline space */
        !          1328: 
        !          1329:        addr = (vm_offset_t)pages;
        !          1330:        potential = *countp;
        !          1331: 
        !          1332:        for (;;) {
        !          1333:                vstruct_t       entry;
        !          1334: 
        !          1335:                VSL_LOCK();
        !          1336:                queue_iterate(&vstruct_list.vsl_queue, entry, vstruct_t,
        !          1337:                              vs_links) {
        !          1338:                        VS_LOCK(entry);
        !          1339:                        if (entry->vs_object_name == object) {
        !          1340:                                VSL_UNLOCK();
        !          1341:                                goto found_object;
        !          1342:                        }
        !          1343:                        VS_UNLOCK(entry);
        !          1344:                }
        !          1345:                VSL_UNLOCK();
        !          1346: 
        !          1347:                /* did not find the object */
        !          1348: 
        !          1349:                if (pages != *pagesp)
        !          1350:                        (void) vm_deallocate(kernel_map, addr, size);
        !          1351:                return KERN_INVALID_ARGUMENT;
        !          1352: 
        !          1353:            found_object:
        !          1354: 
        !          1355:                if (!VS_MAP_TRY_LOCK(entry)) {
        !          1356:                        /* oh well bad luck */
        !          1357: 
        !          1358:                        VS_UNLOCK(entry);
        !          1359: 
        !          1360:                        assert_wait_timeout( 1, THREAD_INTERRUPTIBLE);
        !          1361:                        thread_block((void (*)(void)) 0);
        !          1362:                        thread_cancel_timer();
        !          1363:                        continue;
        !          1364:                }
        !          1365: 
        !          1366:                actual = ps_vstruct_allocated_pages(entry, pages, potential);
        !          1367:                VS_MAP_UNLOCK(entry);
        !          1368:                VS_UNLOCK(entry);
        !          1369: 
        !          1370:                if (actual <= potential)
        !          1371:                        break;
        !          1372: 
        !          1373:                /* allocate more memory */
        !          1374: 
        !          1375:                if (pages != *pagesp)
        !          1376:                        (void) vm_deallocate(kernel_map, addr, size);
        !          1377:                size = round_page(actual * sizeof * pages);
        !          1378:                kr = vm_allocate(kernel_map, &addr, size, TRUE);
        !          1379:                if (kr != KERN_SUCCESS)
        !          1380:                        return kr;
        !          1381:                pages = (default_pager_page_t *)addr;
        !          1382:                potential = size / sizeof * pages;
        !          1383:        }
        !          1384: 
        !          1385:        /*
        !          1386:         * Deallocate and clear unused memory.
        !          1387:         * (Returned memory will automagically become pageable.)
        !          1388:         */
        !          1389: 
        !          1390:        if (pages == *pagesp) {
        !          1391: 
        !          1392:                /*
        !          1393:                 * Our returned information fit inline.
        !          1394:                 * Nothing to deallocate.
        !          1395:                 */
        !          1396: 
        !          1397:                *countp = actual;
        !          1398:        } else if (actual == 0) {
        !          1399:                (void) vm_deallocate(kernel_map, addr, size);
        !          1400: 
        !          1401:                /* return zero items inline */
        !          1402:                *countp = 0;
        !          1403:        } else {
        !          1404:                vm_offset_t used;
        !          1405: 
        !          1406:                used = round_page(actual * sizeof * pages);
        !          1407: 
        !          1408:                if (used != size)
        !          1409:                        (void) vm_deallocate(kernel_map,
        !          1410:                                             addr + used, size - used);
        !          1411: 
        !          1412:                *pagesp = pages;
        !          1413:                *countp = actual;
        !          1414:        }
        !          1415:        (void) vm_map_unwire(kernel_map, (vm_offset_t)pages, 
        !          1416:                        *countp + (vm_offset_t)pages, FALSE); 
        !          1417:        (void) vm_map_copyin(kernel_map, (vm_offset_t)pages, 
        !          1418:                        *countp, TRUE, (vm_map_copy_t *)pagesp);
        !          1419:        return KERN_SUCCESS;
        !          1420: }

unix.superglobalmegacorp.com

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