-#define HI_WATER_DEFAULT 40000000
-#define MINIMUM_SIZE (1024 * 1024 * 64)
-#define MAXIMUM_SIZE (1024 * 1024 * 1024)
-
-#define MAX_LIMITS 8
-
-#if TARGET_OS_EMBEDDED
-
-#include <System/sys/content_protection.h>
-
-#define USE_SYSTEMCONFIGURATION_PRIVATE_HEADERS 1
-#include <SystemConfiguration/SystemConfiguration.h>
-
-enum {
- VM_PAGING_MODE_DISABLED = 0,
- VM_PAGING_MODE_FREEZE,
- VM_PAGING_MODE_DYNAMIC
-};
-
-#define VM_FREEZE_SYSCTL "vm.freeze_enabled"
-#define FREEZE_FIXED_SWAP_SIZE (128 * 1024 * 1024)
-#endif
-
-struct limit {
- unsigned int size;
- unsigned int low_water;
-} limits[MAX_LIMITS];
-
-
-int debug = 0;
-int max_valid = 0;
-int file_count = 0;
-unsigned int hi_water;
-unsigned int local_hi_water;
-int priority = 0;
-int options = 0;
-char fileroot[512];
-
-
-/* global parameters for application notification option */
-mach_port_t trigger_port = MACH_PORT_NULL;
-mach_port_t notify_port = MACH_PORT_NULL;
-unsigned int notify_high = 0;
-unsigned int bs_recovery;
-
-/*
-void setprof __P((struct kvmvars *kvp, int state));
-void dumpstate __P((struct kvmvars *kvp));
-void reset __P((struct kvmvars *kvp));
-*/
-
-
-
-mach_msg_return_t
-server_alert_loop(
- mach_msg_size_t max_size,
- mach_port_t rcv_name,
- mach_msg_options_t options)
-{
- mig_reply_error_t *bufRequest = 0, *bufReply = 0;
- register mach_msg_return_t mr;
- register kern_return_t kr;
-
- if ((kr = vm_allocate(mach_task_self(),
- (vm_address_t *)&bufRequest,
- max_size + MAX_TRAILER_SIZE,
- TRUE)) != KERN_SUCCESS)
- return kr;
- mlock(bufRequest, max_size + MAX_TRAILER_SIZE);
- if ((kr = vm_allocate(mach_task_self(),
- (vm_address_t *)&bufReply,
- max_size + MAX_TRAILER_SIZE,
- TRUE)) != KERN_SUCCESS)
- return kr;
- mlock(bufReply, max_size + MAX_TRAILER_SIZE);
- while(TRUE) {
- mr = mach_msg(&bufRequest->Head, MACH_RCV_MSG|options,
- 0, max_size, rcv_name,
- MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
- if (mr == MACH_MSG_SUCCESS) {
- /* we have a request message */
-
- if(!(default_pager_alerts_server(
- &bufRequest->Head, &bufReply->Head)))
- backing_store_triggers_server(
- &bufRequest->Head, &bufReply->Head);
-
- if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
- bufReply->RetCode != KERN_SUCCESS) {
- if (bufReply->RetCode == MIG_NO_REPLY)
- /*
- * This return code is a little tricky--
- * it appears that the demux routine found an
- * error of some sort, but since that error
- * would not normally get returned either to
- * the local user or the remote one, we pretend it's
- * ok.
- */
-
- bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
- mach_msg_destroy(&bufRequest->Head);
- continue;
- }
-
- if (bufReply->Head.msgh_remote_port == MACH_PORT_NULL) {
- /* no reply port, so destroy the reply */
- if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
- mach_msg_destroy(&bufReply->Head);
- } else {
- break;
- }
- } else {
- break;
- }
- }
-
- (void)vm_deallocate(mach_task_self(),
- (vm_address_t) bufRequest,
- max_size + MAX_TRAILER_SIZE);
- (void)vm_deallocate(mach_task_self(),
- (vm_address_t) bufReply,
- max_size + MAX_TRAILER_SIZE);
- return KERN_FAILURE;
-
-}
-
-
-kern_return_t
-backing_store_triggers(dynamic_pager, hi_wat, flags, port)
- mach_port_t dynamic_pager;
- int hi_wat;
- int flags;
- mach_port_t port;
-{
- int cur_limits;
-
- if (file_count > max_valid)
- cur_limits = max_valid;
- else
- cur_limits = file_count;
-
- if((hi_wat + limits[cur_limits].size) > limits[cur_limits].low_water)
- return KERN_FAILURE; /* let ipc system clean up port */
-
- /* If there was a previous registration, throw it away */
- if (notify_port != MACH_PORT_NULL) {
- mach_port_deallocate(mach_task_self(), notify_port);
- notify_port = MACH_PORT_NULL;
- }
-
- notify_port = port;
- notify_high = hi_wat;
- if(hi_water < notify_high) {
- local_hi_water = notify_high;
- } else {
- local_hi_water = hi_water;
- }
- if(notify_high > hi_water) {
- default_pager_space_alert(trigger_port, HI_WAT_ALERT);
- }
- return KERN_SUCCESS;
-}
-
-
-kern_return_t
-default_pager_space_alert(alert_port, flags)
- mach_port_t alert_port;
- int flags;
-{
- char subfile[512];
- off_t filesize;
- int error=0, fd=0;
- kern_return_t ret;
- int cur_limits;
- unsigned int cur_size;
- unsigned int notifications;
-
-
- if(flags & HI_WAT_ALERT) {
-
- file_count++;
-
- if (file_count > max_valid)
- cur_limits = max_valid;
- else
- cur_limits = file_count;
-
- cur_size = limits[cur_limits].size;
- filesize = cur_size;
-
- /*
- * because the LO_WAT threshold changes relative to
- * the size of the swap file we're creating
- * we need to reset the LO_WAT_ALERT threshold each
- * time we create a new swap file
- */
- if (limits[cur_limits].low_water)
- notifications = HI_WAT_ALERT | LO_WAT_ALERT;
- else
- notifications = HI_WAT_ALERT;
-
- sprintf(subfile, "%s%d", fileroot, file_count);
- fd = open(subfile, O_CREAT|O_EXCL|O_RDWR,(mode_t)(S_IRUSR|S_IWUSR));
- if (fd == -1) {
- /* force error recovery below */
- error = -1;
- }
-#if TARGET_OS_EMBEDDED
- else {
- error = fcntl(fd, F_SETPROTECTIONCLASS, PROTECTION_CLASS_F);
- }
-#endif
-
- if(!error) {
- error = fcntl(fd, F_SETSIZE, &filesize);
- if(error) {
- error = ftruncate(fd, filesize);
- }
- if(error)
- unlink(subfile);
- close(fd);
- }
-
- if(error == -1) {
- file_count--;
-
- if (file_count > max_valid)
- cur_limits = max_valid;
- else
- cur_limits = file_count;
-
- if (limits[cur_limits].low_water)
- notifications = HI_WAT_ALERT | LO_WAT_ALERT;
- else
- notifications = HI_WAT_ALERT;
-
- notifications |= SWAP_FILE_CREATION_ERROR;
-
- local_hi_water = local_hi_water>>2;
- if(notify_high >= (local_hi_water)) {
- if(notify_port != MACH_PORT_NULL) {
- /* notify monitoring app of */
- /* backing store shortage */
- backing_store_alert(notify_port,
- HI_WAT_ALERT);
- mach_port_deallocate(mach_task_self(),
- notify_port);
- notify_port = MACH_PORT_NULL;
- notify_high = 0;
- }
- }
- } else {
- if(hi_water < notify_high) {
- if(local_hi_water < notify_high) {
- bs_recovery = notify_high - local_hi_water;
- }
- local_hi_water = notify_high;
- } else {
- if(local_hi_water < hi_water) {
- bs_recovery = hi_water - local_hi_water;
- }
- local_hi_water = hi_water;
- }
- ret = macx_swapon((uint64_t)(uintptr_t)subfile,
- flags, cur_size, priority);
-
- if(ret) {
- unlink(subfile);
- file_count--;
-
- if (file_count > max_valid)
- cur_limits = max_valid;
- else
- cur_limits = file_count;
-
- if (limits[cur_limits].low_water)
- notifications = HI_WAT_ALERT | LO_WAT_ALERT;
- else
- notifications = HI_WAT_ALERT;
-
- local_hi_water = local_hi_water>>2;
- if(notify_high >= (local_hi_water)) {
- if(notify_port != MACH_PORT_NULL) {
- /* notify monitoring app of */
- /* backing store shortage */
- backing_store_alert(
- notify_port,
- HI_WAT_ALERT);
- mach_port_deallocate(
- mach_task_self(),
- notify_port);
- notify_port = MACH_PORT_NULL;
- notify_high = 0;
- }
- }
- } else if(bs_recovery <= cur_size) {
- if((bs_recovery != 0) && (notify_port)) {
- backing_store_alert(notify_port,
- LO_WAT_ALERT);
- mach_port_deallocate(mach_task_self(),
- notify_port);
- notify_port = MACH_PORT_NULL;
- notify_high = 0;
- bs_recovery = 0;
- }
- } else
- bs_recovery = bs_recovery-cur_size;
- }
- macx_triggers(local_hi_water, limits[cur_limits].low_water, notifications, alert_port);
- }
- if(flags & LO_WAT_ALERT) {
- sprintf(subfile, "%s%d", fileroot, file_count);
- if(hi_water < notify_high) {
- local_hi_water = notify_high;
- } else {
- local_hi_water = hi_water;
- }
- if((bs_recovery != 0) && (notify_port != MACH_PORT_NULL)) {
- backing_store_alert(notify_port, LO_WAT_ALERT);
- mach_port_deallocate(mach_task_self(), notify_port);
- notify_port = MACH_PORT_NULL;
- notify_high = 0;
- bs_recovery = 0;
- }
- if((error = macx_swapoff((uint64_t)(uintptr_t)subfile,
- flags)) == 0) {
-
- unlink(subfile);
- file_count--;
-
- if (file_count > max_valid)
- cur_limits = max_valid;
- else
- cur_limits = file_count;
- } else {
- if (file_count > max_valid)
- cur_limits = max_valid;
- else
- cur_limits = file_count;
- }
- /*
- * only need to reset the LO_WAT_ALERT... the HI_WAT size is fixed,
- * it doesn't change even if the swap file size shrinks or grows
- */
- macx_triggers(local_hi_water, limits[cur_limits].low_water, LO_WAT_ALERT, alert_port);
- }
- return KERN_SUCCESS;
-}
-
-void
-wait_on_paging_trigger(trigger_port)
- mach_port_t trigger_port;
-{
- kern_return_t result;
- result = server_alert_loop(4096, trigger_port, MACH_MSG_OPTION_NONE);
- if (result != KERN_SUCCESS) {
- fprintf(stderr, "dynamic_pager: default pager alert failed\n");
- exit(EXIT_FAILURE);
- }
- exit(EXIT_SUCCESS);
-}
-
-void
-paging_setup(flags, size, priority, low, high, encrypted)
- int flags;
- int size;
- int priority;
- int low;
- int high;
- boolean_t encrypted;
-{
- off_t filesize = size;
- char subfile[512];
- int error, fd = 0;
-
- file_count = 0;
- sprintf(subfile, "%s%d", fileroot, file_count);
- fd = open(subfile, O_CREAT|O_EXCL|O_RDWR, ((mode_t)(S_IRUSR|S_IWUSR)));
- if (fd == -1) {
- fprintf(stderr, "dynamic_pager: cannot create paging file %s!\n",
- subfile);
- exit(EXIT_FAILURE);
- }
-
-#if TARGET_OS_EMBEDDED
- error = fcntl(fd, F_SETPROTECTIONCLASS, PROTECTION_CLASS_F);
- if (error == -1) {
- fprintf(stderr, "dynamic_pager: cannot set file protection class!\n");
- unlink(subfile);
- close(fd);
- exit(EXIT_FAILURE);
- }
-#endif
-
- error = fcntl(fd, F_SETSIZE, &filesize);
- if(error) {
- error = ftruncate(fd, filesize);
- }
- close(fd);
-
- if (error == -1) {
- fprintf(stderr, "dynamic_pager: cannot extend paging file size %s to %llu!\n",
- subfile, filesize);
- exit(EXIT_FAILURE);
- }
-
- if (macx_triggers(0, 0,
- (encrypted
- ? SWAP_ENCRYPT_ON
- : SWAP_ENCRYPT_OFF),
- MACH_PORT_NULL) != 0) {
- fprintf(stderr,
- "dynamic_pager: warning: "
- "could not turn encrypted swap %s\n",
- (encrypted ? "on" : "off"));
- }
-
- macx_swapon((uint64_t)(uintptr_t)subfile, flags, size, priority);
-
- if(hi_water) {
- mach_msg_type_name_t poly;
-
- if (mach_port_allocate(mach_task_self(),
- MACH_PORT_RIGHT_RECEIVE,
- &trigger_port) != KERN_SUCCESS) {
- fprintf(stderr,"dynamic_pager: allocation of trigger port failed\n");
- exit(EXIT_FAILURE);
- }
- /* create a send right on our local port */
- mach_port_extract_right(mach_task_self(), trigger_port,
- MACH_MSG_TYPE_MAKE_SEND, &trigger_port, &poly);
- macx_triggers(high, low, HI_WAT_ALERT, trigger_port);
-
- if(low) {
- macx_triggers(high, low, LO_WAT_ALERT, trigger_port);
- }
- /* register control port for applications wishing to */
- /* get backing store notifications or change dynamic */
- /* pager settings. */
- set_dp_control_port(mach_host_self(), trigger_port);
- wait_on_paging_trigger(trigger_port);
- }
- exit(EXIT_SUCCESS);
-}