]>
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; | |
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; | |
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 | { | |
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; | |
1815bff5 A |
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) { | |
1c51fdde A |
297 | mach_msg_type_name_t poly; |
298 | ||
1815bff5 A |
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 | } | |
1c51fdde A |
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); | |
1815bff5 A |
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 | } |