]>
Commit | Line | Data |
---|---|---|
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 | ||
38 | int debug = 0; | |
39 | int file_count = 0; | |
20e66415 A |
40 | int low_water = 0; |
41 | int hi_water = 0; | |
42 | int local_hi_water = 0; | |
43 | int size = 20000000; | |
1815bff5 | 44 | int priority = 0; |
20e66415 | 45 | int options = 0; |
1815bff5 A |
46 | char fileroot[512]; |
47 | ||
48 | ||
49 | /* global parameters for application notification option */ | |
756446ec A |
50 | mach_port_t trigger_port = MACH_PORT_NULL; |
51 | mach_port_t notify_port = MACH_PORT_NULL; | |
20e66415 A |
52 | int notify_high = 0; |
53 | int bs_recovery; | |
1815bff5 A |
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; | |
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 | ||
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 | { | |
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 | ||
178 | kern_return_t | |
179 | default_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 | ||
292 | void | |
293 | wait_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 | ||
305 | void | |
306 | paging_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 | } |
356 | int | |
357 | main(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 | } |