From fce4daf20cca97ada666b0a1e41c52d8387f265b Mon Sep 17 00:00:00 2001 From: Maksym Planeta Date: Mon, 8 Oct 2012 16:01:13 +0200 Subject: Add IPC functions that allow user to manipulate with memory advice. * include/mach/mach_types.defs (vm_advice_t): New type definition. * include/mach/mach.defs (vm_advice): New RPC definition. (memory_object_set_advice): Likewise. (memory_object_get_advice): Likewise. * kern/ipc_mig.c (syscall_vm_advice): New function. This is optimization function for RPC that is processed by kernel. * kern/syscall_sw.c (syscall_vm_advice): Add function prototype. (mach_trap_table): Add syscall_vm_advice to trap table. * vm/memory_object.c (memory_object_set_advice): New function. Sets memory advice for memory object. (memory_object_get_advice): New function. Returns memory advice of memory object. * vm/vm_user.c (vm_advice): New function. Wrapper for vm_map_advice. * vm/vm_map.h (vm_map_advice): Add function prototype. * vm/vm_map.c (vm_map_advice): New function. Sets memory advice for memory range. --- include/mach/mach.defs | 23 +++++++++++++++++++--- include/mach/mach_types.defs | 1 + kern/ipc_mig.c | 20 +++++++++++++++++++ kern/syscall_sw.c | 3 ++- vm/memory_object.c | 47 ++++++++++++++++++++++++++++++++++++++++++++ vm/vm_map.c | 42 +++++++++++++++++++++++++++++++++++++++ vm/vm_map.h | 3 +++ vm/vm_user.c | 28 ++++++++++++++++++++++++++ 8 files changed, 163 insertions(+), 4 deletions(-) diff --git a/include/mach/mach.defs b/include/mach/mach.defs index 58510805..c5ffbc05 100644 --- a/include/mach/mach.defs +++ b/include/mach/mach.defs @@ -282,7 +282,18 @@ routine vm_statistics( target_task : vm_task_t; out vm_stats : vm_statistics_data_t); -skip; /* old task_by_u*x_pid */ + +/* + * Set the page fault policy attribute for the specified range + * of the virtual address space of the target task. + * The advice value is either random or sequential, and + * specifies how kernel should consider access to lacking page. + */ +routine vm_advise( + target_task : vm_task_t; + address : vm_address_t; + size : vm_size_t; + advice : vm_advice_t); skip; /* old vm_pageable */ /* @@ -681,8 +692,14 @@ simpleroutine memory_object_change_attributes( MACH_MSG_TYPE_MAKE_SEND_ONCE|polymorphic); skip; /* old host_callout_statistics_reset */ -skip; /* old port_set_select */ -skip; /* old port_set_backup */ + +simpleroutine memory_object_set_advice( + memory_control : memory_object_control_t; + advice : vm_advice_t); + +routine memory_object_get_advice( + memory_control : memory_object_control_t; + out advice : vm_advice_t); /* * Set/Get special properties of memory associated diff --git a/include/mach/mach_types.defs b/include/mach/mach_types.defs index 607d5d92..12c4b7c7 100644 --- a/include/mach/mach_types.defs +++ b/include/mach/mach_types.defs @@ -117,6 +117,7 @@ type vm_offset_t = natural_t; type vm_size_t = natural_t; type vm_prot_t = int; type vm_inherit_t = int; +type vm_advice_t = int; type vm_statistics_data_t = struct[13] of integer_t; type vm_machine_attribute_t = int; type vm_machine_attribute_val_t = int; diff --git a/kern/ipc_mig.c b/kern/ipc_mig.c index 3f55da7c..38f74136 100644 --- a/kern/ipc_mig.c +++ b/kern/ipc_mig.c @@ -704,6 +704,26 @@ kern_return_t syscall_vm_deallocate(target_map, start, size) return result; } +kern_return_t +syscall_vm_advise( + mach_port_t target_map, + vm_offset_t address, + vm_size_t length, + vm_advice_t advice, + vm_size_t cluster_size) +{ + vm_map_t map; + kern_return_t result; + + map = port_name_to_map(target_map); + if (map == VM_MAP_NULL) + return MACH_SEND_INTERRUPTED; + + result = vm_advise(map, address, length, advice, cluster_size); + + return result; +} + kern_return_t syscall_task_create(parent_task, inherit_memory, child_task) mach_port_t parent_task; boolean_t inherit_memory; diff --git a/kern/syscall_sw.c b/kern/syscall_sw.c index b2e20e66..659cac89 100644 --- a/kern/syscall_sw.c +++ b/kern/syscall_sw.c @@ -73,6 +73,7 @@ kern_return_t kern_invalid() extern kern_return_t syscall_vm_map(); extern kern_return_t syscall_vm_allocate(); extern kern_return_t syscall_vm_deallocate(); +extern kern_return_t syscall_vm_advise(); extern kern_return_t syscall_task_create(); extern kern_return_t syscall_task_terminate(); @@ -164,7 +165,7 @@ mach_trap_t mach_trap_table[] = { MACH_TRAP(syscall_vm_map, 11), /* 64 */ MACH_TRAP(syscall_vm_allocate, 4), /* 65 */ MACH_TRAP(syscall_vm_deallocate, 3), /* 66 */ - MACH_TRAP(kern_invalid, 0), /* 67 */ + MACH_TRAP(syscall_vm_advise, 5), /* 67 */ MACH_TRAP(syscall_task_create, 3), /* 68 */ MACH_TRAP(syscall_task_terminate, 1), /* 69 */ diff --git a/vm/memory_object.c b/vm/memory_object.c index e281c6a3..57c42cd5 100644 --- a/vm/memory_object.c +++ b/vm/memory_object.c @@ -1037,6 +1037,53 @@ kern_return_t memory_object_get_attributes(object, object_ready, return(KERN_SUCCESS); } +kern_return_t +memory_object_set_advice(object, advice) + vm_object_t object; + vm_advice_t advice; +{ + if (object == VM_OBJECT_NULL) + return(KERN_INVALID_ARGUMENT); + + switch(advice) { + case VM_ADVICE_DEFAULT: + case VM_ADVICE_RANDOM: + case VM_ADVICE_SEQUENTIAL: + case VM_ADVICE_NORMAL: + case VM_ADVICE_KEEP: + break; + default: + vm_object_deallocate(object); + return(KERN_INVALID_ARGUMENT); + } + + vm_object_lock(object); + if (advice != VM_ADVICE_KEEP) + object->advice = advice; + vm_object_unlock(object); + + vm_object_deallocate(object); + + return(KERN_SUCCESS); +} + +kern_return_t +memory_object_get_advice(object, advice) + vm_object_t object; + vm_advice_t *advice; +{ + if (object == VM_OBJECT_NULL) + return(KERN_INVALID_ARGUMENT); + + vm_object_lock(object); + *advice = object->advice; + vm_object_unlock(object); + + vm_object_deallocate(object); + + return(KERN_SUCCESS); +} + /* * If successful, consumes the supplied naked send right. */ diff --git a/vm/vm_map.c b/vm/vm_map.c index 22fe0eae..b307c663 100644 --- a/vm/vm_map.c +++ b/vm/vm_map.c @@ -1345,6 +1345,48 @@ kern_return_t vm_map_inherit(map, start, end, new_inheritance) return(KERN_SUCCESS); } +/* + * vm_map_advise: + * + * Sets the page fault advice of the specified + * address range in the target map. Advice + * affects how the page fault will be + * handled at the time of vm_fault. + */ +kern_return_t vm_map_advise(map, address, length, advice) + vm_map_t map; + vm_offset_t address; + vm_size_t length; + vm_advice_t advice; +{ + register vm_map_entry_t entry; + vm_map_entry_t temp_entry; + vm_offset_t end = address + length; + + vm_map_lock(map); + + VM_MAP_RANGE_CHECK(map, address, end); + + if (vm_map_lookup_entry(map, address, &temp_entry)) { + entry = temp_entry; + vm_map_clip_start(map, entry, address); + } + else + entry = temp_entry->vme_next; + + while ((entry != vm_map_to_entry(map)) + && (entry->vme_start < end)) { + vm_map_clip_end(map, entry, end); + + entry->advice = advice; + + entry = entry->vme_next; + } + + vm_map_unlock(map); + return(KERN_SUCCESS); +} + /* * vm_map_pageable_common: * diff --git a/vm/vm_map.h b/vm/vm_map.h index af7588ba..4b4520db 100644 --- a/vm/vm_map.h +++ b/vm/vm_map.h @@ -397,6 +397,9 @@ extern kern_return_t vm_map_protect(vm_map_t, vm_offset_t, vm_offset_t, /* Change inheritance */ extern kern_return_t vm_map_inherit(vm_map_t, vm_offset_t, vm_offset_t, vm_inherit_t); +/* Change page fault policy */ +extern kern_return_t vm_map_advice(vm_map_t, vm_offset_t, vm_size_t, + vm_advice_t, vm_size_t); /* Debugging: print a map */ extern void vm_map_print(vm_map_t); diff --git a/vm/vm_user.c b/vm/vm_user.c index 59c2a36e..614bd604 100644 --- a/vm/vm_user.c +++ b/vm/vm_user.c @@ -171,6 +171,34 @@ kern_return_t vm_protect(map, start, size, set_maximum, new_protection) set_maximum)); } + +/* + * vm_advise sets page fault handling policy of the specified range + * in the specified map. + */ + +kern_return_t vm_advise(map, address, length, advice) + vm_map_t map; + vm_offset_t address; + vm_size_t length; + vm_advice_t advice; +{ + if (map == VM_MAP_NULL) + return(KERN_INVALID_ARGUMENT); + + switch(advice) { + case VM_ADVICE_DEFAULT: + case VM_ADVICE_RANDOM: + case VM_ADVICE_SEQUENTIAL: + case VM_ADVICE_NORMAL: + break; + default: + return(KERN_INVALID_ARGUMENT); + } + + return(vm_map_advise(map, address, length, advice)); +} + kern_return_t vm_statistics(map, stat) vm_map_t map; vm_statistics_data_t *stat; -- cgit v1.2.3