2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
26 * Mach Operating System
27 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
28 * All Rights Reserved.
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.
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.
40 * Carnegie Mellon requests users of this software to return to
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
53 * Memory Object Management.
56 #include "default_pager_internal.h"
57 #include <mach/memory_object_server.h>
58 #include <vm/vm_pageout.h> /* include for upl_t */
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
70 struct vstruct_list_head vstruct_list
;
72 void vstruct_list_insert(vstruct_t vs
); /* forward */
79 queue_enter(&vstruct_list
.vsl_queue
, vs
, vstruct_t
, vs_links
);
80 vstruct_list
.vsl_count
++;
84 void vstruct_list_delete(vstruct_t vs
); /* forward */
90 queue_remove(&vstruct_list
.vsl_queue
, vs
, vstruct_t
, vs_links
);
91 vstruct_list
.vsl_count
--;
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.
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 */
110 void vs_async_wait(vstruct_t
); /* forward */
116 static char here
[] = "vs_async_wait";
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
);
123 thread_block((void (*)(void))0);
126 ASSERT(vs
->vs_async_pending
== 0);
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
);
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.
153 mach_port_seqno_t seqno
)
155 default_pager_total
++;
158 seqno
= vs
->vs_next_seqno
++;
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
);
165 thread_block((void (*)(void))0);
171 * Increments sequence number and unlocks pager.
174 vs_unlock(vstruct_t vs
)
176 boolean_t need_wakeups
= vs
->vs_waiting_seqno
;
178 vs
->vs_waiting_seqno
= FALSE
;
182 thread_wakeup(&vs
->vs_waiting_seqno
);
186 * Start a read - one more reader. Pager must be locked.
196 * Wait for readers. Unlocks and relocks pager if wait needed.
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
);
207 thread_block((void (*)(void))0);
213 * Finish a read. Pager is unlocked and returns unlocked.
220 if (--vs
->vs_readers
== 0) {
221 boolean_t need_wakeups
= vs
->vs_waiting_read
;
223 vs
->vs_waiting_read
= FALSE
;
226 thread_wakeup(&vs
->vs_waiting_read
);
232 * Start a write - one more writer. Pager must be locked.
242 * Wait for writers. Unlocks and relocks pager if wait needed.
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
);
253 thread_block((void (*)(void))0);
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 */
265 vs_wait_for_sync_writers(
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
);
273 thread_block((void (*)(void))0);
280 * Finish a write. Pager is unlocked and returns unlocked.
287 if (--vs
->vs_writers
== 0) {
288 boolean_t need_wakeups
= vs
->vs_waiting_write
;
290 vs
->vs_waiting_write
= FALSE
;
293 thread_wakeup(&vs
->vs_waiting_write
);
299 * Wait for concurrent default_pager_objects.
300 * Unlocks and relocks pager if wait needed.
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
);
311 thread_block((void (*)(void))0);
317 * Finished creating name refs - wake up waiters.
323 boolean_t need_wakeups
= vs
->vs_waiting_refs
;
324 vs
->vs_waiting_refs
= FALSE
;
326 thread_wakeup(&vs
->vs_waiting_refs
);
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)
343 #endif /* PARALLEL */
345 vstruct_t
vs_object_create(vm_size_t
); /* forward */
352 static char here
[] = "vs_object_create";
355 * Allocate a vstruct. If there are any problems, then report them
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"));
368 mach_port_urefs_t default_pager_max_urefs
= 10000;
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.
375 void vs_check_request(vstruct_t
, MACH_PORT_FACE
); /* forward */
380 MACH_PORT_FACE control_port
)
382 mach_port_delta_t delta
;
384 static char here
[] = "vs_check_request";
386 if (++vs
->vs_control_refs
> default_pager_max_urefs
) {
387 delta
= 1 - vs
->vs_control_refs
;
388 vs
->vs_control_refs
= 1;
393 * Deallocate excess user references.
397 /* find a better interface for this, what will we use as a component */
400 for(i
=0; i
<delta
; i
++)
401 ipc_port_release_send(control_port
);
408 void default_pager_add(vstruct_t
, boolean_t
); /* forward */
415 MACH_PORT_FACE mem_obj
= vs
->vs_mem_obj_port
;
417 mach_port_mscount_t sync
;
418 MACH_PORT_FACE previous
;
420 static char here
[] = "default_pager_add";
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.
429 /* possibly generate an immediate no-senders notification */
431 pset
= default_pager_internal_set
;
433 /* delay notification till send right is created */
435 pset
= default_pager_external_set
;
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
);
445 * Routine: dp_memory_object_create
447 * Handle requests for memory objects from the
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.
455 dp_memory_object_create(
457 MACH_PORT_FACE
*new_mem_obj
,
460 mach_port_seqno_t seqno
;
462 MACH_PORT_FACE pager
;
463 static char here
[] = "memory_object_create";
465 assert(dmm
== default_pager_default_port
);
467 vs
= vs_object_create(new_size
);
468 if (vs
== VSTRUCT_NULL
)
469 return KERN_RESOURCE_SHORTAGE
;
471 pager
= *new_mem_obj
= ipc_port_alloc_kernel();
472 assert (pager
!= IP_NULL
);
473 (void) ipc_port_make_send(pager
);
476 struct vstruct_alias
*alias_struct
;
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
;
485 else Panic("Out of kernel memory");
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
;
494 * Set up associations between this port
495 * and this default_pager structure
498 vs
->vs_mem_obj_port
= pager
;
501 * After this, other threads might receive requests
502 * for this memory object or find it in the port list.
505 vstruct_list_insert(vs
);
506 default_pager_add(vs
, TRUE
);
512 dp_memory_object_init(
513 MACH_PORT_FACE mem_obj
,
514 MACH_PORT_FACE control_port
,
515 vm_size_t pager_page_size
)
517 mach_port_seqno_t seqno
;
519 static char here
[] = "memory_object_init";
521 assert(pager_page_size
== vm_page_size
);
523 vs_lookup(mem_obj
, vs
);
526 if (vs
->vs_control_port
!= MACH_PORT_NULL
)
527 Panic("bad request");
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;
540 dp_memory_object_synchronize(
541 MACH_PORT_FACE mem_obj
,
542 MACH_PORT_FACE control_port
,
543 vm_object_offset_t offset
,
547 mach_port_seqno_t seqno
;
549 static char here
[] = "memory_object_synchronize";
551 vs_lookup(mem_obj
, vs
);
553 vs_check_request(vs
, control_port
);
556 memory_object_synchronize_completed(
557 vm_object_lookup(control_port
),
564 dp_memory_object_terminate(
565 MACH_PORT_FACE mem_obj
,
566 MACH_PORT_FACE control_port
)
568 mach_port_seqno_t seqno
;
570 mach_port_urefs_t request_refs
;
572 static char here
[] = "memory_object_terminate";
575 * control port is a receive right, not a send right.
578 vs_lookup(mem_obj
, vs
);
582 * Wait for read and write requests to terminate.
585 vs_wait_for_readers(vs
);
586 vs_wait_for_writers(vs
);
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
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.
599 vs_wait_for_refs(vs
);
601 vs
->vs_control_port
= MACH_PORT_NULL
;
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 ... */
610 thread_wakeup(&vs
->vs_waiting_write
);
611 thread_wakeup(&vs
->vs_waiting_async
);
613 request_refs
= vs
->vs_control_refs
;
614 vs
->vs_control_refs
= 0;
616 vs
->vs_object_name
= MACH_PORT_NULL
;
618 assert(vs
->vs_name_refs
!= 0);
619 vs
->vs_name_refs
= 0;
624 * Now we deallocate our various port rights.
629 for(i
=0; i
<request_refs
; i
++)
630 ipc_port_release_send(control_port
);
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
);
640 default_pager_no_senders(
641 MACH_PORT_FACE mem_obj
,
642 mach_port_seqno_t seqno
,
643 mach_port_mscount_t mscount
)
646 static char here
[] = "default_pager_no_senders";
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.
656 vs_lookup(mem_obj
, vs
);
658 vs_async_wait(vs
); /* wait for pending async IO */
660 /* do not delete the vs structure until the referencing pointers */
661 /* in the vstruct list have been expunged */
663 /* get VSL_LOCK out of order by using TRY mechanism */
664 while(!VSL_LOCK_TRY()) {
669 vs_async_wait(vs
); /* wait for pending async IO */
672 * We shouldn't get a no-senders notification
673 * when the kernel has the object cached.
675 if (vs
->vs_control_port
!= MACH_PORT_NULL
)
676 Panic("bad request");
679 * Unlock the pager (though there should be no one
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.
690 vstruct_list_delete(vs
);
691 ps_vstruct_dealloc(vs
);
694 * Recover memory that we might have wasted because
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
,
701 kfree((vm_offset_t
) vs
, sizeof *vs
);
707 dp_memory_object_data_request(
708 MACH_PORT_FACE mem_obj
,
709 MACH_PORT_FACE reply_to
,
710 vm_object_offset_t offset
,
712 vm_prot_t protection_required
)
714 mach_port_seqno_t seqno
;
716 static char here
[] = "memory_object_data_request";
718 GSTAT(global_stats
.gs_pagein_calls
++);
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
);
726 vs_check_request(vs
, reply_to
);
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 */
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
);
744 thread_block((void (*)(void))0);
748 if(vs
->vs_control_port
== MACH_PORT_NULL
) {
760 * Request must be on a page boundary and a multiple of pages.
762 if ((offset
& vm_page_mask
) != 0 || (length
& vm_page_mask
) != 0)
763 Panic("bad alignment");
765 pvs_cluster_read(vs
, (vm_offset_t
)offset
, length
);
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.
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 */
785 dp_memory_object_data_initialize(
786 MACH_PORT_FACE mem_obj
,
787 MACH_PORT_FACE control_port
,
788 vm_object_offset_t offset
,
792 mach_port_seqno_t seqno
;
794 static char here
[] = "memory_object_data_initialize";
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
));
805 vs_lookup(mem_obj
, vs
);
807 vs_check_request(vs
, control_port
);
812 * Write the data via clustered writes. vs_cluster_write will
813 * loop if the address range specified crosses cluster
816 vs_cluster_write(vs
, 0, (vm_offset_t
)offset
, data_cnt
, FALSE
, 0);
824 dp_memory_object_lock_completed(
825 memory_object_t mem_obj
,
826 MACH_PORT_FACE control_port
,
827 vm_object_offset_t offset
,
830 mach_port_seqno_t seqno
;
831 static char here
[] = "memory_object_lock_completed";
846 dp_memory_object_data_unlock(
847 memory_object_t mem_obj
,
848 MACH_PORT_FACE control_port
,
849 vm_object_offset_t offset
,
851 vm_prot_t desired_access
)
853 static char here
[] = "memory_object_data_unlock";
861 dp_memory_object_supply_completed(
862 memory_object_t mem_obj
,
863 MACH_PORT_FACE control_port
,
864 vm_object_offset_t offset
,
866 kern_return_t result
,
867 vm_offset_t error_offset
)
869 static char here
[] = "memory_object_supply_completed";
876 dp_memory_object_data_return(
877 MACH_PORT_FACE mem_obj
,
878 MACH_PORT_FACE control_port
,
879 vm_object_offset_t offset
,
883 boolean_t kernel_copy
)
885 mach_port_seqno_t seqno
;
887 static char here
[] = "memory_object_data_return";
895 DEBUG(DEBUG_MO_EXTERNAL
,
896 ("mem_obj=0x%x,offset=0x%x,addr=0x%xcnt=0x%x\n",
897 (int)mem_obj
, (int)offset
, (int)addr
, (int)data_cnt
));
898 GSTAT(global_stats
.gs_pageout_calls
++);
900 /* This routine is called by the pageout thread. The pageout thread */
901 /* cannot be blocked by read activities unless the read activities */
902 /* Therefore the grant of vs lock must be done on a try versus a */
903 /* blocking basis. The code below relies on the fact that the */
904 /* interface is synchronous. Should this interface be again async */
905 /* for some type of pager in the future the pages will have to be */
906 /* returned through a separate, asynchronous path. */
908 vs_lookup(mem_obj
, vs
);
910 default_pager_total
++;
911 if(!VS_TRY_LOCK(vs
)) {
912 /* the call below will not be done by caller when we have */
913 /* a synchronous interface */
914 /* return KERN_LOCK_OWNED; */
916 upl_system_list_request((vm_object_t
)
917 vs
->vs_control_port
->ip_kobject
,
918 offset
, data_cnt
, data_cnt
, &upl
, NULL
, 0,
919 UPL_NOBLOCK
| UPL_CLEAN_IN_PLACE
920 | UPL_NO_SYNC
| UPL_COPYOUT_FROM
);
922 ipc_port_release_send(control_port
);
928 if ((vs
->vs_seqno
!= vs
->vs_next_seqno
++) || (vs
->vs_xfer_pending
)) {
932 /* the call below will not be done by caller when we have */
933 /* a synchronous interface */
934 /* return KERN_LOCK_OWNED; */
935 upl_system_list_request((vm_object_t
)
936 vs
->vs_control_port
->ip_kobject
,
937 offset
, data_cnt
, data_cnt
, &upl
, NULL
, 0,
938 UPL_NOBLOCK
| UPL_CLEAN_IN_PLACE
939 | UPL_NO_SYNC
| UPL_COPYOUT_FROM
);
941 ipc_port_release_send(control_port
);
945 if ((data_cnt
% vm_page_size
) != 0)
946 Panic("bad alignment");
951 vs
->vs_async_pending
+= 1; /* protect from backing store contraction */
953 /* unroll vs_check_request to avoid re-locking vs */
955 if (++vs
->vs_control_refs
> default_pager_max_urefs
) {
956 mach_port_delta_t delta
;
958 delta
= 1 - vs
->vs_control_refs
;
959 vs
->vs_control_refs
= 1;
964 * Deallocate excess user references.
970 for(i
=0; i
<delta
; i
++)
971 ipc_port_release_send(control_port
);
979 * Write the data via clustered writes. vs_cluster_write will
980 * loop if the address range specified crosses cluster
983 vs_cluster_write(vs
, 0, (vm_offset_t
)offset
, data_cnt
, FALSE
, 0);
987 /* temporary, need a finer lock based on cluster */
990 vs
->vs_async_pending
-= 1; /* release vs_async_wait */
991 if (vs
->vs_async_pending
== 0) {
993 thread_wakeup(&vs
->vs_waiting_async
);
1003 dp_memory_object_change_completed(
1004 memory_object_t mem_obj
,
1005 memory_object_control_t memory_control
,
1006 memory_object_flavor_t flavor
)
1008 static char here
[] = "memory_object_change_completed";
1011 return KERN_FAILURE
;
1015 * Create an external object.
1018 default_pager_object_create(
1019 MACH_PORT_FACE pager
,
1020 MACH_PORT_FACE
*mem_obj
,
1024 MACH_PORT_FACE port
;
1025 kern_return_t result
;
1026 struct vstruct_alias
*alias_struct
;
1027 static char here
[] = "default_pager_object_create";
1030 if (pager
!= default_pager_default_port
)
1031 return KERN_INVALID_ARGUMENT
;
1033 vs
= vs_object_create(size
);
1035 port
= ipc_port_alloc_kernel();
1036 ipc_port_make_send(port
);
1037 /* register abstract memory object port with pager mux routine */
1038 /* (directs kernel internal calls to the right pager). */
1039 alias_struct
= (struct vstruct_alias
*)
1040 kalloc(sizeof(struct vstruct_alias
));
1041 if(alias_struct
!= NULL
) {
1042 alias_struct
->vs
= vs
;
1043 alias_struct
->name
= ISVS
;
1044 port
->alias
= (int) alias_struct
;
1046 else Panic("Out of kernel memory");
1049 * Set up associations between these ports
1050 * and this vstruct structure
1053 vs
->vs_mem_obj_port
= port
;
1054 vstruct_list_insert(vs
);
1055 default_pager_add(vs
, FALSE
);
1059 return KERN_SUCCESS
;
1063 default_pager_objects(
1064 MACH_PORT_FACE pager
,
1065 default_pager_object_array_t
*objectsp
,
1066 mach_msg_type_number_t
*ocountp
,
1067 mach_port_array_t
*portsp
,
1068 mach_msg_type_number_t
*pcountp
)
1070 vm_offset_t oaddr
= 0; /* memory for objects */
1071 vm_size_t osize
= 0; /* current size */
1072 default_pager_object_t
* objects
;
1073 unsigned int opotential
;
1075 vm_offset_t paddr
= 0; /* memory for ports */
1076 vm_size_t psize
= 0; /* current size */
1077 MACH_PORT_FACE
* ports
;
1078 unsigned int ppotential
;
1080 unsigned int actual
;
1081 unsigned int num_objects
;
1084 static char here
[] = "default_pager_objects";
1086 if (pager != default_pager_default_port)
1087 return KERN_INVALID_ARGUMENT;
1090 /* start with the inline memory */
1092 kr
= vm_map_copyout(ipc_kernel_map
, (vm_offset_t
*)&objects
,
1093 (vm_map_copy_t
) *objectsp
);
1095 if (kr
!= KERN_SUCCESS
)
1098 osize
= round_page(*ocountp
* sizeof * objects
);
1099 kr
= vm_map_wire(ipc_kernel_map
,
1100 trunc_page((vm_offset_t
)objects
),
1101 round_page(((vm_offset_t
)objects
) + osize
),
1102 VM_PROT_READ
|VM_PROT_WRITE
, FALSE
);
1105 *objectsp
= objects
;
1106 /* we start with the inline space */
1110 opotential
= *ocountp
;
1112 ports
= (MACH_PORT_FACE
*) *portsp
;
1113 ppotential
= *pcountp
;
1118 * We will send no more than this many
1120 actual
= vstruct_list
.vsl_count
;
1123 if (opotential
< actual
) {
1124 vm_offset_t newaddr
;
1127 newsize
= 2 * round_page(actual
* sizeof * objects
);
1129 kr
= vm_allocate(kernel_map
, &newaddr
, newsize
, TRUE
);
1130 if (kr
!= KERN_SUCCESS
)
1135 opotential
= osize
/ sizeof * objects
;
1136 objects
= (default_pager_object_t
*)oaddr
;
1139 if (ppotential
< actual
) {
1140 vm_offset_t newaddr
;
1143 newsize
= 2 * round_page(actual
* sizeof * ports
);
1145 kr
= vm_allocate(kernel_map
, &newaddr
, newsize
, TRUE
);
1146 if (kr
!= KERN_SUCCESS
)
1151 ppotential
= psize
/ sizeof * ports
;
1152 ports
= (MACH_PORT_FACE
*)paddr
;
1156 * Now scan the list.
1162 queue_iterate(&vstruct_list
.vsl_queue
, entry
, vstruct_t
, vs_links
) {
1164 MACH_PORT_FACE port
;
1167 if ((num_objects
>= opotential
) ||
1168 (num_objects
>= ppotential
)) {
1171 * This should be rare. In any case,
1172 * we will only miss recent objects,
1173 * because they are added at the end.
1179 * Avoid interfering with normal operations
1181 if (!VS_MAP_TRY_LOCK(entry
))
1183 size
= ps_vstruct_allocated_size(entry
);
1184 VS_MAP_UNLOCK(entry
);
1188 port
= entry
->vs_object_name
;
1189 if (port
== MACH_PORT_NULL
) {
1192 * The object is waiting for no-senders
1193 * or memory_object_init.
1200 * We need a reference for the reply message.
1201 * While we are unlocked, the bucket queue
1202 * can change and the object might be terminated.
1203 * memory_object_terminate will wait for us,
1204 * preventing deallocation of the entry.
1207 if (--entry
->vs_name_refs
== 0) {
1210 /* keep the list locked, wont take long */
1214 for(i
=0; i
<default_pager_max_urefs
; i
++)
1215 ipc_port_make_send(port
);
1219 entry
->vs_name_refs
+= default_pager_max_urefs
;
1220 vs_finish_refs(entry
);
1224 /* the arrays are wired, so no deadlock worries */
1226 objects
[num_objects
].dpo_object
= (vm_offset_t
) entry
;
1227 objects
[num_objects
].dpo_size
= size
;
1228 ports
[num_objects
++] = port
;
1233 * Do not return garbage
1235 objects
[num_objects
].dpo_object
= (vm_offset_t
) 0;
1236 objects
[num_objects
].dpo_size
= 0;
1237 ports
[num_objects
++] = MACH_PORT_NULL
;
1244 * Deallocate and clear unused memory.
1245 * (Returned memory will automagically become pageable.)
1248 if (objects
== *objectsp
) {
1251 * Our returned information fit inline.
1252 * Nothing to deallocate.
1254 *ocountp
= num_objects
;
1255 } else if (actual
== 0) {
1256 (void) vm_deallocate(kernel_map
, oaddr
, osize
);
1258 /* return zero items inline */
1263 used
= round_page(actual
* sizeof * objects
);
1266 (void) vm_deallocate(kernel_map
,
1267 oaddr
+ used
, osize
- used
);
1269 *objectsp
= objects
;
1270 *ocountp
= num_objects
;
1273 if (ports
== (MACH_PORT_FACE
*)*portsp
) {
1276 * Our returned information fit inline.
1277 * Nothing to deallocate.
1280 *pcountp
= num_objects
;
1281 } else if (actual
== 0) {
1282 (void) vm_deallocate(kernel_map
, paddr
, psize
);
1284 /* return zero items inline */
1289 used
= round_page(actual
* sizeof * ports
);
1292 (void) vm_deallocate(kernel_map
,
1293 paddr
+ used
, psize
- used
);
1295 *portsp
= (mach_port_array_t
)ports
;
1296 *pcountp
= num_objects
;
1298 (void) vm_map_unwire(kernel_map
, (vm_offset_t
)objects
,
1299 *ocountp
+ (vm_offset_t
)objects
, FALSE
);
1300 (void) vm_map_copyin(kernel_map
, (vm_offset_t
)objects
,
1301 *ocountp
, TRUE
, (vm_map_copy_t
*)objectsp
);
1303 return KERN_SUCCESS
;
1308 for (i
= 0; i
< num_objects
; i
++)
1309 ipc_port_dealloc_kernel(ports
[i
]);
1312 if (objects
!= *objectsp
)
1313 (void) vm_deallocate(kernel_map
, oaddr
, osize
);
1315 if (ports
!= (MACH_PORT_FACE
*)*portsp
)
1316 (void) vm_deallocate(kernel_map
, paddr
, psize
);
1318 return KERN_RESOURCE_SHORTAGE
;
1322 default_pager_object_pages(
1323 MACH_PORT_FACE pager
,
1324 MACH_PORT_FACE object
,
1325 default_pager_page_array_t
*pagesp
,
1326 mach_msg_type_number_t
*countp
)
1328 vm_offset_t addr
; /* memory for page offsets */
1329 vm_size_t size
= 0; /* current memory size */
1330 default_pager_page_t
* pages
;
1331 unsigned int potential
, actual
;
1335 if (pager != default_pager_default_port)
1336 return KERN_INVALID_ARGUMENT;
1338 kr
= vm_map_copyout(ipc_kernel_map
, (vm_offset_t
*)&pages
,
1339 (vm_map_copy_t
) *pagesp
);
1341 if (kr
!= KERN_SUCCESS
)
1344 size
= round_page(*countp
* sizeof * pages
);
1345 kr
= vm_map_wire(ipc_kernel_map
,
1346 trunc_page((vm_offset_t
)pages
),
1347 round_page(((vm_offset_t
)pages
) + size
),
1348 VM_PROT_READ
|VM_PROT_WRITE
, FALSE
);
1352 /* we start with the inline space */
1354 addr
= (vm_offset_t
)pages
;
1355 potential
= *countp
;
1361 queue_iterate(&vstruct_list
.vsl_queue
, entry
, vstruct_t
,
1364 if (entry
->vs_object_name
== object
) {
1372 /* did not find the object */
1374 if (pages
!= *pagesp
)
1375 (void) vm_deallocate(kernel_map
, addr
, size
);
1376 return KERN_INVALID_ARGUMENT
;
1380 if (!VS_MAP_TRY_LOCK(entry
)) {
1381 /* oh well bad luck */
1386 assert_wait_timeout( 1, THREAD_INTERRUPTIBLE
);
1387 wait_result
= thread_block((void (*)(void)) 0);
1388 if (wait_result
!= THREAD_TIMED_OUT
)
1389 thread_cancel_timer();
1393 actual
= ps_vstruct_allocated_pages(entry
, pages
, potential
);
1394 VS_MAP_UNLOCK(entry
);
1397 if (actual
<= potential
)
1400 /* allocate more memory */
1402 if (pages
!= *pagesp
)
1403 (void) vm_deallocate(kernel_map
, addr
, size
);
1404 size
= round_page(actual
* sizeof * pages
);
1405 kr
= vm_allocate(kernel_map
, &addr
, size
, TRUE
);
1406 if (kr
!= KERN_SUCCESS
)
1408 pages
= (default_pager_page_t
*)addr
;
1409 potential
= size
/ sizeof * pages
;
1413 * Deallocate and clear unused memory.
1414 * (Returned memory will automagically become pageable.)
1417 if (pages
== *pagesp
) {
1420 * Our returned information fit inline.
1421 * Nothing to deallocate.
1425 } else if (actual
== 0) {
1426 (void) vm_deallocate(kernel_map
, addr
, size
);
1428 /* return zero items inline */
1433 used
= round_page(actual
* sizeof * pages
);
1436 (void) vm_deallocate(kernel_map
,
1437 addr
+ used
, size
- used
);
1442 (void) vm_map_unwire(kernel_map
, (vm_offset_t
)pages
,
1443 *countp
+ (vm_offset_t
)pages
, FALSE
);
1444 (void) vm_map_copyin(kernel_map
, (vm_offset_t
)pages
,
1445 *countp
, TRUE
, (vm_map_copy_t
*)pagesp
);
1446 return KERN_SUCCESS
;