]> git.saurik.com Git - apple/system_cmds.git/blob - dynamic_pager.tproj/dynamic_pager.c
system_cmds-230.0.2.tar.gz
[apple/system_cmds.git] / dynamic_pager.tproj / dynamic_pager.c
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
38 int debug = 0;
39 int file_count = 0;
40 int low_water = 0;
41 int hi_water = 0;
42 int local_hi_water = 0;
43 int size = 20000000;
44 int priority = 0;
45 int options = 0;
46 char fileroot[512];
47
48
49 /* global parameters for application notification option */
50 mach_port_t trigger_port = NULL;
51 mach_port_t notify_port = NULL;
52 int notify_high = 0;
53 int bs_recovery;
54
55 /*
56 void setprof __P((struct kvmvars *kvp, int state));
57 void dumpstate __P((struct kvmvars *kvp));
58 void reset __P((struct kvmvars *kvp));
59 */
60
61
62
63 mach_msg_return_t
64 server_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;
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;
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;
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;
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
148 kern_return_t
149 backing_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 {
155 if((hi_wat + size) > low_water)
156 return KERN_FAILURE; /* let ipc system clean up port */
157 notify_port = port;
158 notify_high = hi_wat;
159 if(hi_water < notify_high) {
160 local_hi_water = notify_high;
161 } else {
162 local_hi_water = hi_water;
163 }
164 if(notify_high > hi_water) {
165 default_pager_space_alert(trigger_port, HI_WAT_ALERT);
166 }
167 return KERN_SUCCESS;
168 }
169
170
171 kern_return_t
172 default_pager_space_alert(alert_port, flags)
173 mach_port_t alert_port;
174 int flags;
175 {
176 char subfile[512];
177 FILE *file_ptr;
178 off_t filesize = size;
179 int error;
180
181 if(flags & HI_WAT_ALERT) {
182 /* printf("HI WAT ALERT!!\n"); */
183 file_count++;
184 sprintf(subfile, "%s%d", fileroot, file_count);
185 file_ptr = fopen(subfile, "w+");
186 fchmod(fileno(file_ptr), (mode_t)01600);
187 error = fcntl(fileno(file_ptr), F_SETSIZE, &filesize);
188 fclose(file_ptr);
189 if(error == -1) {
190 unlink(subfile);
191 file_count--;
192 local_hi_water = local_hi_water>>2;
193 if(notify_high >= (local_hi_water)) {
194 if(notify_port) {
195 /* notify monitoring app of */
196 /* backing store shortage */
197 backing_store_alert(notify_port,
198 HI_WAT_ALERT);
199 mach_port_deallocate(mach_task_self(),
200 notify_port);
201 notify_high = 0;
202 notify_port = 0;
203 }
204 }
205 macx_triggers(local_hi_water,
206 low_water, HI_WAT_ALERT, alert_port);
207 } else {
208 if(hi_water < notify_high) {
209 if(local_hi_water < notify_high) {
210 bs_recovery = notify_high - local_hi_water;
211 }
212 local_hi_water = notify_high;
213 } else {
214 if(local_hi_water < hi_water) {
215 bs_recovery = hi_water - local_hi_water;
216 }
217 local_hi_water = hi_water;
218 }
219 macx_swapon(subfile, flags, size, priority);
220 if(bs_recovery <= size) {
221 if((bs_recovery != 0) && (notify_port)) {
222 backing_store_alert(notify_port,
223 LO_WAT_ALERT);
224 mach_port_deallocate(mach_task_self(),
225 notify_port);
226 notify_high = 0;
227 notify_port = NULL;
228
229 bs_recovery = 0;
230 }
231 } else
232 bs_recovery = bs_recovery-size;
233 }
234
235 macx_triggers(local_hi_water,
236 low_water, HI_WAT_ALERT, alert_port);
237 }
238 if(flags & LO_WAT_ALERT) {
239 /* Turn into a logged message printf("LO WAT ALERT!!\n"); */
240 sprintf(subfile, "%s%d", fileroot, file_count);
241 if(hi_water < notify_high) {
242 local_hi_water = notify_high;
243 } else {
244 local_hi_water = hi_water;
245 }
246 if((bs_recovery != 0) && (notify_port)) {
247 backing_store_alert(notify_port, LO_WAT_ALERT);
248 mach_port_deallocate(mach_task_self(), notify_port);
249 notify_high = 0;
250 notify_port = NULL;
251
252 bs_recovery = 0;
253 }
254 if(macx_swapoff(subfile, flags) == 0) {
255 unlink(subfile);
256 file_count--;
257 }
258 macx_triggers(local_hi_water, low_water, LO_WAT_ALERT, alert_port);
259 }
260 return KERN_SUCCESS;
261 }
262
263 void
264 wait_on_paging_trigger(trigger_port)
265 mach_port_t trigger_port;
266 {
267 kern_return_t result;
268 result = server_alert_loop(4096, trigger_port, MACH_MSG_OPTION_NONE);
269 if (result != KERN_SUCCESS) {
270 fprintf(stderr, "dynamic_pager: default pager alert failed\n");
271 exit(1);
272 }
273 exit(0);
274 }
275
276 void
277 paging_setup(flags, size, priority, low, high)
278 int flags;
279 int size;
280 int priority;
281 int low;
282 int high;
283 {
284 off_t filesize = size;
285 char subfile[512];
286 FILE *file_ptr;
287
288 file_count = 0;
289 sprintf(subfile, "%s%d", fileroot, file_count);
290 file_ptr = fopen(subfile, "w+");
291 fchmod(fileno(file_ptr), (mode_t)01600);
292 fcntl(fileno(file_ptr), F_SETSIZE, &filesize);
293 fclose(file_ptr);
294
295 macx_swapon(subfile, flags, size, priority);
296 if(hi_water) {
297 mach_msg_type_name_t poly;
298
299 daemon(0,0);
300
301 if (mach_port_allocate(mach_task_self(),
302 MACH_PORT_RIGHT_RECEIVE,
303 &trigger_port) != KERN_SUCCESS) {
304 fprintf(stderr,"allocation of trigger port failed\n");
305 exit(1);
306 }
307 /* create a send right on our local port */
308 mach_port_extract_right(mach_task_self(), trigger_port,
309 MACH_MSG_TYPE_MAKE_SEND, &trigger_port, &poly);
310 macx_triggers(high, low, HI_WAT_ALERT, trigger_port);
311 if(low) {
312 macx_triggers(high,
313 low, LO_WAT_ALERT, trigger_port);
314 }
315 /* register control port for applications wishing to */
316 /* get backing store notifications or change dynamic */
317 /* pager settings. */
318 set_dp_control_port(mach_host_self(), trigger_port);
319 wait_on_paging_trigger(trigger_port);
320 }
321 exit(0);
322 }
323 int
324 main(int argc, char **argv)
325 {
326 extern char *optarg;
327 extern int optind;
328 char default_filename[] = "/private/var/vm/swapfile";
329 int ch;
330
331 seteuid(getuid());
332 strcpy(fileroot, default_filename);
333
334 while ((ch = getopt(argc, argv, "F:L:H:S:P:O:")) != EOF) {
335 switch((char)ch) {
336
337 case 'F':
338 strncpy(fileroot, optarg, 500);
339 break;
340
341 case 'L':
342 low_water = atoi(optarg);
343 break;
344 case 'H':
345 hi_water = atoi(optarg);
346 break;
347 case 'S':
348 size = atoi(optarg);
349 break;
350 case 'P':
351 priority = atoi(optarg);
352 break;
353
354 default:
355 (void)fprintf(stderr,
356 "usage: dynamic_pager [-F filename] [-L low water alert trigger] [-H high water alert trigger] [-S file size] [-P priority]\n");
357 exit(1);
358 }
359 }
360 local_hi_water = hi_water;
361 if((low_water != 0) && (low_water <= (size + hi_water))) {
362 (void)fprintf(stderr, "usage: low water trigger must be larger than size + hi_water\n");
363 exit(1);
364 }
365 argc -= optind;
366 argv += optind;
367 paging_setup(0, size, priority, low_water, hi_water);
368 return (0);
369 }