]> git.saurik.com Git - apple/system_cmds.git/blame - dynamic_pager.tproj/dynamic_pager.c
system_cmds-258.tar.gz
[apple/system_cmds.git] / dynamic_pager.tproj / dynamic_pager.c
CommitLineData
1815bff5
A
1/* File created by Chris Youngworth, Apple Computer 2/11/99 */
2
3
4#define mig_external
5
6#include <mach/port.h>
7#include <mach/mach_error.h>
8#include <mach/mach_traps.h>
9#include <mach/mach.h>
10#ifndef MACH_BSD
11#define MACH_BSD
12#endif
13#include <mach/bootstrap.h>
14#include <mach/mach_syscalls.h>
15#include <mach/mig_errors.h>
16#include <sys/param.h>
17#include <sys/file.h>
18#include <sys/mman.h>
19#include <sys/stat.h>
20#include <sys/sysctl.h>
21#include <sys/gmon.h>
22#include <errno.h>
23#include <kvm.h>
24#include <limits.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <nlist.h>
29#include <ctype.h>
30#include <unistd.h>
31#include <paths.h>
32
33#include <default_pager/default_pager_types.h>
34#include <default_pager_alerts_server.h>
35#include <backing_store_alerts.h>
36#include <backing_store_triggers_server.h>
37
38int debug = 0;
39int file_count = 0;
20e66415
A
40int low_water = 0;
41int hi_water = 0;
42int local_hi_water = 0;
43int size = 20000000;
1815bff5 44int priority = 0;
20e66415 45int options = 0;
1815bff5
A
46char fileroot[512];
47
48
49/* global parameters for application notification option */
756446ec
A
50mach_port_t trigger_port = MACH_PORT_NULL;
51mach_port_t notify_port = MACH_PORT_NULL;
20e66415
A
52int notify_high = 0;
53int bs_recovery;
1815bff5
A
54
55/*
56void setprof __P((struct kvmvars *kvp, int state));
57void dumpstate __P((struct kvmvars *kvp));
58void reset __P((struct kvmvars *kvp));
59*/
60
61
62
63mach_msg_return_t
64server_alert_loop(
65 mach_msg_size_t max_size,
66 mach_port_t rcv_name,
67 mach_msg_options_t options)
68{
69 mig_reply_error_t *bufRequest = 0, *bufReply = 0;
70 register mach_msg_return_t mr;
71 register kern_return_t kr;
72
73 if ((kr = vm_allocate(mach_task_self(),
74 (vm_address_t *)&bufRequest,
75 max_size + MAX_TRAILER_SIZE,
76 TRUE)) != KERN_SUCCESS)
77 return kr;
1c51fdde
A
78 if ((kr = vm_protect(mach_task_self(),
79 (vm_address_t)bufRequest,
80 max_size + MAX_TRAILER_SIZE,
81 FALSE, VM_PROT_ALL)) != KERN_SUCCESS)
82 return kr;
1815bff5
A
83 mlock(bufRequest, max_size + MAX_TRAILER_SIZE);
84 if ((kr = vm_allocate(mach_task_self(),
85 (vm_address_t *)&bufReply,
86 max_size + MAX_TRAILER_SIZE,
87 TRUE)) != KERN_SUCCESS)
88 return kr;
1c51fdde
A
89 if ((kr = vm_protect(mach_task_self(),
90 (vm_address_t)bufReply,
91 max_size + MAX_TRAILER_SIZE,
92 FALSE, VM_PROT_ALL)) != KERN_SUCCESS)
93 return kr;
1815bff5
A
94 mlock(bufReply, max_size + MAX_TRAILER_SIZE);
95 while(TRUE) {
96 mr = mach_msg_overwrite_trap(&bufRequest->Head, MACH_RCV_MSG|options,
97 0, max_size, rcv_name,
98 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL,
99 (mach_msg_header_t *) 0, 0);
100 if (mr == MACH_MSG_SUCCESS) {
101 /* we have a request message */
102
103 if(!(default_pager_alerts_server(
104 &bufRequest->Head, &bufReply->Head)))
105 backing_store_triggers_server(
106 &bufRequest->Head, &bufReply->Head);
107
108 if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
109 bufReply->RetCode != KERN_SUCCESS) {
110 if (bufReply->RetCode == MIG_NO_REPLY)
111 /*
112 * This return code is a little tricky--
113 * it appears that the demux routine found an
114 * error of some sort, but since that error
115 * would not normally get returned either to
116 * the local user or the remote one, we pretend it's
117 * ok.
118 */
119
120 bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
121 mach_msg_destroy(&bufRequest->Head);
122 continue;
123 }
124
125 if (bufReply->Head.msgh_remote_port == MACH_PORT_NULL) {
126 /* no reply port, so destroy the reply */
127 if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
128 mach_msg_destroy(&bufReply->Head);
129 } else {
130 break;
131 }
132 } else {
133 break;
134 }
135 }
136
137 (void)vm_deallocate(mach_task_self(),
138 (vm_address_t) bufRequest,
139 max_size + MAX_TRAILER_SIZE);
140 (void)vm_deallocate(mach_task_self(),
141 (vm_address_t) bufReply,
142 max_size + MAX_TRAILER_SIZE);
143 return KERN_FAILURE;
144
145}
146
147
148kern_return_t
149backing_store_triggers(dynamic_pager, hi_wat, flags, port)
150 mach_port_t dynamic_pager;
151 int hi_wat;
152 int flags;
153 mach_port_t port;
154{
20e66415 155 if((hi_wat + size) > low_water)
1815bff5 156 return KERN_FAILURE; /* let ipc system clean up port */
756446ec
A
157
158 /* If there was a previous registration, throw it away */
159 if (notify_port != MACH_PORT_NULL) {
160 mach_port_deallocate(mach_task_self(), notify_port);
161 notify_port = MACH_PORT_NULL;
162 }
163
1815bff5
A
164 notify_port = port;
165 notify_high = hi_wat;
166 if(hi_water < notify_high) {
167 local_hi_water = notify_high;
168 } else {
169 local_hi_water = hi_water;
170 }
171 if(notify_high > hi_water) {
172 default_pager_space_alert(trigger_port, HI_WAT_ALERT);
173 }
174 return KERN_SUCCESS;
175}
176
177
178kern_return_t
179default_pager_space_alert(alert_port, flags)
180 mach_port_t alert_port;
181 int flags;
182{
183 char subfile[512];
184 FILE *file_ptr;
20e66415 185 off_t filesize = size;
1815bff5 186 int error;
756446ec 187 kern_return_t ret;
1815bff5
A
188
189 if(flags & HI_WAT_ALERT) {
20e66415 190/* printf("HI WAT ALERT!!\n"); */
1815bff5
A
191 file_count++;
192 sprintf(subfile, "%s%d", fileroot, file_count);
193 file_ptr = fopen(subfile, "w+");
194 fchmod(fileno(file_ptr), (mode_t)01600);
195 error = fcntl(fileno(file_ptr), F_SETSIZE, &filesize);
756446ec 196 if(error) {
20e66415 197 error = ftruncate(fileno(file_ptr), (off_t)size);
756446ec 198 }
1815bff5
A
199 fclose(file_ptr);
200 if(error == -1) {
201 unlink(subfile);
202 file_count--;
203 local_hi_water = local_hi_water>>2;
204 if(notify_high >= (local_hi_water)) {
756446ec 205 if(notify_port != MACH_PORT_NULL) {
1815bff5
A
206 /* notify monitoring app of */
207 /* backing store shortage */
208 backing_store_alert(notify_port,
209 HI_WAT_ALERT);
210 mach_port_deallocate(mach_task_self(),
211 notify_port);
756446ec 212 notify_port = MACH_PORT_NULL;
1815bff5 213 notify_high = 0;
1815bff5
A
214 }
215 }
20e66415
A
216 macx_triggers(local_hi_water,
217 low_water, HI_WAT_ALERT, alert_port);
1815bff5
A
218 } else {
219 if(hi_water < notify_high) {
220 if(local_hi_water < notify_high) {
221 bs_recovery = notify_high - local_hi_water;
222 }
223 local_hi_water = notify_high;
224 } else {
225 if(local_hi_water < hi_water) {
226 bs_recovery = hi_water - local_hi_water;
227 }
228 local_hi_water = hi_water;
229 }
20e66415 230 ret = macx_swapon(subfile, flags, size, priority);
756446ec
A
231 if(ret) {
232 unlink(subfile);
233 file_count--;
756446ec
A
234 local_hi_water = local_hi_water>>2;
235 if(notify_high >= (local_hi_water)) {
236 if(notify_port != MACH_PORT_NULL) {
237 /* notify monitoring app of */
238 /* backing store shortage */
239 backing_store_alert(
240 notify_port,
241 HI_WAT_ALERT);
242 mach_port_deallocate(
243 mach_task_self(),
244 notify_port);
245 notify_port = MACH_PORT_NULL;
246 notify_high = 0;
247 }
248 }
20e66415
A
249 macx_triggers(local_hi_water,
250 low_water, HI_WAT_ALERT, alert_port);
251 } else if(bs_recovery <= size) {
1815bff5
A
252 if((bs_recovery != 0) && (notify_port)) {
253 backing_store_alert(notify_port,
254 LO_WAT_ALERT);
255 mach_port_deallocate(mach_task_self(),
256 notify_port);
756446ec 257 notify_port = MACH_PORT_NULL;
1815bff5 258 notify_high = 0;
1815bff5
A
259 bs_recovery = 0;
260 }
261 } else
20e66415 262 bs_recovery = bs_recovery-size;
1815bff5 263 }
20e66415
A
264
265 macx_triggers(local_hi_water,
266 low_water, HI_WAT_ALERT, alert_port);
1815bff5
A
267 }
268 if(flags & LO_WAT_ALERT) {
20e66415 269/* Turn into a logged message printf("LO WAT ALERT!!\n"); */
1815bff5
A
270 sprintf(subfile, "%s%d", fileroot, file_count);
271 if(hi_water < notify_high) {
272 local_hi_water = notify_high;
273 } else {
274 local_hi_water = hi_water;
275 }
756446ec 276 if((bs_recovery != 0) && (notify_port != MACH_PORT_NULL)) {
1815bff5
A
277 backing_store_alert(notify_port, LO_WAT_ALERT);
278 mach_port_deallocate(mach_task_self(), notify_port);
756446ec 279 notify_port = MACH_PORT_NULL;
1815bff5 280 notify_high = 0;
1815bff5
A
281 bs_recovery = 0;
282 }
20e66415 283 if(macx_swapoff(subfile, flags) == 0) {
1815bff5
A
284 unlink(subfile);
285 file_count--;
286 }
20e66415 287 macx_triggers(local_hi_water, low_water, LO_WAT_ALERT, alert_port);
1815bff5
A
288 }
289 return KERN_SUCCESS;
290}
291
292void
293wait_on_paging_trigger(trigger_port)
294 mach_port_t trigger_port;
295{
296 kern_return_t result;
297 result = server_alert_loop(4096, trigger_port, MACH_MSG_OPTION_NONE);
298 if (result != KERN_SUCCESS) {
299 fprintf(stderr, "dynamic_pager: default pager alert failed\n");
300 exit(1);
301 }
302 exit(0);
303}
304
305void
306paging_setup(flags, size, priority, low, high)
307 int flags;
308 int size;
309 int priority;
310 int low;
311 int high;
312{
313 off_t filesize = size;
314 char subfile[512];
315 FILE *file_ptr;
756446ec 316 int error;
1815bff5
A
317
318 file_count = 0;
319 sprintf(subfile, "%s%d", fileroot, file_count);
320 file_ptr = fopen(subfile, "w+");
321 fchmod(fileno(file_ptr), (mode_t)01600);
756446ec
A
322 error = fcntl(fileno(file_ptr), F_SETSIZE, &filesize);
323 if(error) {
20e66415 324 error = ftruncate(fileno(file_ptr), (off_t)size);
756446ec 325 }
1815bff5
A
326 fclose(file_ptr);
327
328 macx_swapon(subfile, flags, size, priority);
329 if(hi_water) {
1c51fdde
A
330 mach_msg_type_name_t poly;
331
1815bff5
A
332 daemon(0,0);
333
334 if (mach_port_allocate(mach_task_self(),
335 MACH_PORT_RIGHT_RECEIVE,
336 &trigger_port) != KERN_SUCCESS) {
337 fprintf(stderr,"allocation of trigger port failed\n");
338 exit(1);
339 }
1c51fdde
A
340 /* create a send right on our local port */
341 mach_port_extract_right(mach_task_self(), trigger_port,
342 MACH_MSG_TYPE_MAKE_SEND, &trigger_port, &poly);
1815bff5
A
343 macx_triggers(high, low, HI_WAT_ALERT, trigger_port);
344 if(low) {
20e66415
A
345 macx_triggers(high,
346 low, LO_WAT_ALERT, trigger_port);
1815bff5
A
347 }
348 /* register control port for applications wishing to */
349 /* get backing store notifications or change dynamic */
350 /* pager settings. */
351 set_dp_control_port(mach_host_self(), trigger_port);
352 wait_on_paging_trigger(trigger_port);
353 }
20e66415 354 exit(0);
1815bff5
A
355}
356int
357main(int argc, char **argv)
358{
359 extern char *optarg;
360 extern int optind;
361 char default_filename[] = "/private/var/vm/swapfile";
362 int ch;
363
364 seteuid(getuid());
365 strcpy(fileroot, default_filename);
366
367 while ((ch = getopt(argc, argv, "F:L:H:S:P:O:")) != EOF) {
368 switch((char)ch) {
369
370 case 'F':
371 strncpy(fileroot, optarg, 500);
372 break;
373
374 case 'L':
20e66415 375 low_water = atoi(optarg);
1815bff5
A
376 break;
377 case 'H':
378 hi_water = atoi(optarg);
379 break;
380 case 'S':
20e66415 381 size = atoi(optarg);
1815bff5
A
382 break;
383 case 'P':
384 priority = atoi(optarg);
385 break;
386
387 default:
388 (void)fprintf(stderr,
389 "usage: dynamic_pager [-F filename] [-L low water alert trigger] [-H high water alert trigger] [-S file size] [-P priority]\n");
390 exit(1);
391 }
392 }
393 local_hi_water = hi_water;
20e66415 394 if((low_water != 0) && (low_water <= (size + hi_water))) {
1815bff5
A
395 (void)fprintf(stderr, "usage: low water trigger must be larger than size + hi_water\n");
396 exit(1);
397 }
398 argc -= optind;
399 argv += optind;
20e66415 400 paging_setup(0, size, priority, low_water, hi_water);
1815bff5
A
401 return (0);
402}