]> git.saurik.com Git - apple/xnu.git/blob - libsyscall/wrappers/libproc/libproc.c
xnu-3789.41.3.tar.gz
[apple/xnu.git] / libsyscall / wrappers / libproc / libproc.c
1 /*
2 * Copyright (c) 2006, 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <sys/cdefs.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <strings.h>
29 #include <stdlib.h>
30 #include <sys/errno.h>
31 #include <sys/msgbuf.h>
32 #include <sys/resource.h>
33 #include <sys/process_policy.h>
34 #include <sys/event.h>
35 #include <mach/message.h>
36
37 #include "libproc_internal.h"
38
39 int __proc_info(int callnum, int pid, int flavor, uint64_t arg, void * buffer, int buffersize);
40 __private_extern__ int proc_setthreadname(void * buffer, int buffersize);
41 int __process_policy(int scope, int action, int policy, int policy_subtype, proc_policy_attribute_t * attrp, pid_t target_pid, uint64_t target_threadid);
42 int proc_rlimit_control(pid_t pid, int flavor, void *arg);
43
44 int
45 proc_listpids(uint32_t type, uint32_t typeinfo, void *buffer, int buffersize)
46 {
47 int retval;
48
49 if ((type >= PROC_ALL_PIDS) || (type <= PROC_PPID_ONLY)) {
50 if ((retval = __proc_info(PROC_INFO_CALL_LISTPIDS, type, typeinfo,(uint64_t)0, buffer, buffersize)) == -1)
51 return(0);
52 } else {
53 errno = EINVAL;
54 retval = 0;
55 }
56 return(retval);
57 }
58
59
60 int
61 proc_listallpids(void * buffer, int buffersize)
62 {
63 int numpids;
64 numpids = proc_listpids(PROC_ALL_PIDS, (uint32_t)0, buffer, buffersize);
65
66 if (numpids == -1)
67 return(-1);
68 else
69 return(numpids/sizeof(int));
70 }
71
72 int
73 proc_listpgrppids(pid_t pgrpid, void * buffer, int buffersize)
74 {
75 int numpids;
76 numpids = proc_listpids(PROC_PGRP_ONLY, (uint32_t)pgrpid, buffer, buffersize);
77 if (numpids == -1)
78 return(-1);
79 else
80 return(numpids/sizeof(int));
81 }
82
83 int
84 proc_listchildpids(pid_t ppid, void * buffer, int buffersize)
85 {
86 int numpids;
87 numpids = proc_listpids(PROC_PPID_ONLY, (uint32_t)ppid, buffer, buffersize);
88 if (numpids == -1)
89 return(-1);
90 else
91 return(numpids/sizeof(int));
92 }
93
94
95 int
96 proc_pidinfo(int pid, int flavor, uint64_t arg, void *buffer, int buffersize)
97 {
98 int retval;
99
100 if ((retval = __proc_info(PROC_INFO_CALL_PIDINFO, pid, flavor, arg, buffer, buffersize)) == -1)
101 return(0);
102
103 return(retval);
104 }
105
106
107 int
108 proc_pidoriginatorinfo(int flavor, void *buffer, int buffersize)
109 {
110 int retval;
111
112 if ((retval = __proc_info(PROC_INFO_CALL_PIDORIGINATORINFO, getpid(), flavor, 0, buffer, buffersize)) == -1)
113 return(0);
114
115 return(retval);
116 }
117
118 int
119 proc_listcoalitions(int flavor, int coaltype, void *buffer, int buffersize)
120 {
121 int retval;
122
123 if ((retval = __proc_info(PROC_INFO_CALL_LISTCOALITIONS, flavor, coaltype, 0, buffer, buffersize)) == -1)
124 return 0;
125
126 return retval;
127 }
128
129 int
130 proc_pid_rusage(int pid, int flavor, rusage_info_t *buffer)
131 {
132 return (__proc_info(PROC_INFO_CALL_PIDRUSAGE, pid, flavor, 0, buffer, 0));
133 }
134
135 int
136 proc_setthread_cpupercent(uint8_t percentage, uint32_t ms_refill)
137 {
138 uint32_t arg = 0;
139
140 /* Pack percentage and refill into a 32-bit number to match existing kernel implementation */
141 if ((percentage >= 100) || (ms_refill & ~0xffffffU)) {
142 errno = EINVAL;
143 return -1;
144 }
145
146 arg = ((ms_refill << 8) | percentage);
147
148 return (proc_rlimit_control(-1, RLIMIT_THREAD_CPULIMITS, (void *)(uintptr_t)arg));
149 }
150
151 int
152 proc_pidfdinfo(int pid, int fd, int flavor, void * buffer, int buffersize)
153 {
154 int retval;
155
156 if ((retval = __proc_info(PROC_INFO_CALL_PIDFDINFO, pid, flavor, (uint64_t)fd, buffer, buffersize)) == -1)
157 return(0);
158
159 return (retval);
160 }
161
162
163 int
164 proc_pidfileportinfo(int pid, uint32_t fileport, int flavor, void *buffer, int buffersize)
165 {
166 int retval;
167
168 if ((retval = __proc_info(PROC_INFO_CALL_PIDFILEPORTINFO, pid, flavor, (uint64_t)fileport, buffer, buffersize)) == -1)
169 return (0);
170 return (retval);
171 }
172
173
174 int
175 proc_name(int pid, void * buffer, uint32_t buffersize)
176 {
177 int retval = 0, len;
178 struct proc_bsdinfo pbsd;
179
180
181 if (buffersize < sizeof(pbsd.pbi_name)) {
182 errno = ENOMEM;
183 return(0);
184 }
185
186 retval = proc_pidinfo(pid, PROC_PIDTBSDINFO, (uint64_t)0, &pbsd, sizeof(struct proc_bsdinfo));
187 if (retval != 0) {
188 if (pbsd.pbi_name[0]) {
189 bcopy(&pbsd.pbi_name, buffer, sizeof(pbsd.pbi_name));
190 } else {
191 bcopy(&pbsd.pbi_comm, buffer, sizeof(pbsd.pbi_comm));
192 }
193 len = (int)strlen(buffer);
194 return(len);
195 }
196 return(0);
197 }
198
199 int
200 proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersize)
201 {
202 int retval = 0, len;
203 struct proc_regionwithpathinfo reginfo;
204
205 if (buffersize < MAXPATHLEN) {
206 errno = ENOMEM;
207 return(0);
208 }
209
210 retval = proc_pidinfo(pid, PROC_PIDREGIONPATHINFO, (uint64_t)address, &reginfo, sizeof(struct proc_regionwithpathinfo));
211 if (retval != -1) {
212 len = (int)strlen(&reginfo.prp_vip.vip_path[0]);
213 if (len != 0) {
214 if (len > MAXPATHLEN)
215 len = MAXPATHLEN;
216 bcopy(&reginfo.prp_vip.vip_path[0], buffer, len);
217 return(len);
218 }
219 return(0);
220 }
221 return(0);
222
223 }
224
225 int
226 proc_kmsgbuf(void * buffer, uint32_t buffersize)
227 {
228 int retval;
229
230 if ((retval = __proc_info(PROC_INFO_CALL_KERNMSGBUF, 0, 0, (uint64_t)0, buffer, buffersize)) == -1)
231 return(0);
232 return (retval);
233 }
234
235 int
236 proc_pidpath(int pid, void * buffer, uint32_t buffersize)
237 {
238 int retval, len;
239
240 if (buffersize < PROC_PIDPATHINFO_SIZE) {
241 errno = ENOMEM;
242 return(0);
243 }
244 if (buffersize > PROC_PIDPATHINFO_MAXSIZE) {
245 errno = EOVERFLOW;
246 return(0);
247 }
248
249 retval = __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDPATHINFO, (uint64_t)0, buffer, buffersize);
250 if (retval != -1) {
251 len = (int)strlen(buffer);
252 return(len);
253 }
254 return (0);
255 }
256
257
258 int
259 proc_libversion(int *major, int * minor)
260 {
261
262 if (major != NULL)
263 *major = 1;
264 if (minor != NULL)
265 *minor = 1;
266 return(0);
267 }
268
269 int
270 proc_setpcontrol(const int control)
271 {
272 int retval ;
273
274 if (control < PROC_SETPC_NONE || control > PROC_SETPC_TERMINATE)
275 return(EINVAL);
276
277 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_PCONTROL, (uint64_t)control, NULL, 0)) == -1)
278 return(errno);
279
280 return(0);
281 }
282
283
284 __private_extern__ int
285 proc_setthreadname(void * buffer, int buffersize)
286 {
287 int retval;
288
289 retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_THREADNAME, (uint64_t)0, buffer, buffersize);
290
291 if (retval == -1)
292 return(errno);
293 else
294 return(0);
295 }
296
297 int
298 proc_track_dirty(pid_t pid, uint32_t flags)
299 {
300 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_TRACK, flags, NULL, 0) == -1) {
301 return errno;
302 }
303
304 return 0;
305 }
306
307 int
308 proc_set_dirty(pid_t pid, bool dirty)
309 {
310 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_SET, dirty, NULL, 0) == -1) {
311 return errno;
312 }
313
314 return 0;
315 }
316
317 int
318 proc_get_dirty(pid_t pid, uint32_t *flags)
319 {
320 int retval;
321
322 if (!flags) {
323 return EINVAL;
324 }
325
326 retval = __proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_GET, 0, NULL, 0);
327 if (retval == -1) {
328 return errno;
329 }
330
331 *flags = retval;
332
333 return 0;
334 }
335
336 int
337 proc_clear_dirty(pid_t pid, uint32_t flags)
338 {
339 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_CLEAR, flags, NULL, 0) == -1) {
340 return errno;
341 }
342
343 return 0;
344 }
345
346 int
347 proc_terminate(pid_t pid, int *sig)
348 {
349 int retval;
350
351 if (!sig) {
352 return EINVAL;
353 }
354
355 retval = __proc_info(PROC_INFO_CALL_TERMINATE, pid, 0, 0, NULL, 0);
356 if (retval == -1) {
357 return errno;
358 }
359
360 *sig = retval;
361
362 return 0;
363 }
364
365 /*
366 * XXX the _fatal() variant both checks for an existing monitor
367 * (with important policy effects on first party background apps)
368 * and validates inputs.
369 */
370 int
371 proc_set_cpumon_params(pid_t pid, int percentage, int interval)
372 {
373 proc_policy_cpuusage_attr_t attr;
374
375 /* no argument validation ...
376 * task_set_cpuusage() ignores 0 values and squashes negative
377 * values into uint32_t.
378 */
379
380 attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
381 attr.ppattr_cpu_percentage = percentage;
382 attr.ppattr_cpu_attr_interval = (uint64_t)interval;
383 attr.ppattr_cpu_attr_deadline = 0;
384
385 return(__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
386 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0));
387 }
388
389 int
390 proc_get_cpumon_params(pid_t pid, int *percentage, int *interval)
391 {
392 proc_policy_cpuusage_attr_t attr;
393 int ret;
394
395 ret = __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_GET, PROC_POLICY_RESOURCE_USAGE,
396 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
397
398 if ((ret == 0) && (attr.ppattr_cpu_attr == PROC_POLICY_RSRCACT_NOTIFY_EXC)) {
399 *percentage = attr.ppattr_cpu_percentage;
400 *interval = (int)attr.ppattr_cpu_attr_interval;
401 } else {
402 *percentage = 0;
403 *interval = 0;
404 }
405
406 return (ret);
407 }
408
409 int
410 proc_set_cpumon_defaults(pid_t pid)
411 {
412 proc_policy_cpuusage_attr_t attr;
413
414 attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
415 attr.ppattr_cpu_percentage = PROC_POLICY_CPUMON_DEFAULTS;
416 attr.ppattr_cpu_attr_interval = 0;
417 attr.ppattr_cpu_attr_deadline = 0;
418
419 return(__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
420 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0));
421 }
422
423 int
424 proc_resume_cpumon(pid_t pid)
425 {
426 return __process_policy(PROC_POLICY_SCOPE_PROCESS,
427 PROC_POLICY_ACTION_ENABLE,
428 PROC_POLICY_RESOURCE_USAGE,
429 PROC_POLICY_RUSAGE_CPU,
430 NULL, pid, 0);
431 }
432
433 int
434 proc_disable_cpumon(pid_t pid)
435 {
436 proc_policy_cpuusage_attr_t attr;
437
438 attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
439 attr.ppattr_cpu_percentage = PROC_POLICY_CPUMON_DISABLE;
440 attr.ppattr_cpu_attr_interval = 0;
441 attr.ppattr_cpu_attr_deadline = 0;
442
443 return(__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
444 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0));
445 }
446
447
448 /*
449 * Turn on the CPU usage monitor using the supplied parameters, and make
450 * violations of the monitor fatal.
451 *
452 * Returns: 0 on success;
453 * -1 on failure and sets errno
454 */
455 int
456 proc_set_cpumon_params_fatal(pid_t pid, int percentage, int interval)
457 {
458 int current_percentage = 0;
459 int current_interval = 0; /* intervals are in seconds */
460 int ret = 0;
461
462 if ((percentage <= 0) || (interval <= 0)) {
463 errno = EINVAL;
464 return (-1);
465 }
466
467 /*
468 * Do a simple query to see if CPU monitoring is
469 * already active. If either the percentage or the
470 * interval is nonzero, then CPU monitoring is
471 * already in use for this process.
472 *
473 * XXX: need set...() and set..fatal() to behave similarly.
474 * Currently, this check prevents 1st party apps (which get a
475 * default non-fatal monitor) not to get a fatal monitor.
476 */
477 (void)proc_get_cpumon_params(pid, &current_percentage, &current_interval);
478 if (current_percentage || current_interval)
479 {
480 /*
481 * The CPU monitor appears to be active.
482 * We choose not to disturb those settings.
483 */
484 errno = EBUSY;
485 return (-1);
486 }
487
488 if ((ret = proc_set_cpumon_params(pid, percentage, interval)) != 0) {
489 /* Failed to activate the CPU monitor */
490 return (ret);
491 }
492
493 if ((ret = proc_rlimit_control(pid, RLIMIT_CPU_USAGE_MONITOR, CPUMON_MAKE_FATAL)) != 0) {
494 /* Failed to set termination, back out the CPU monitor settings. */
495 (void)proc_disable_cpumon(pid);
496 }
497
498 return (ret);
499 }
500
501 int
502 proc_set_wakemon_params(pid_t pid, int rate_hz, int flags __unused)
503 {
504 struct proc_rlimit_control_wakeupmon params;
505
506 params.wm_flags = WAKEMON_ENABLE;
507 params.wm_rate = rate_hz;
508
509 return (proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params));
510 }
511
512 #ifndef WAKEMON_GET_PARAMS
513 #define WAKEMON_GET_PARAMS 0x4
514 #define WAKEMON_SET_DEFAULTS 0x8
515 #endif
516
517 int
518 proc_get_wakemon_params(pid_t pid, int *rate_hz, int *flags)
519 {
520 struct proc_rlimit_control_wakeupmon params;
521 int error;
522
523 params.wm_flags = WAKEMON_GET_PARAMS;
524
525 if ((error = proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params)) != 0) {
526 return (error);
527 }
528
529 *rate_hz = params.wm_rate;
530 *flags = params.wm_flags;
531
532 return (0);
533 }
534
535 int
536 proc_set_wakemon_defaults(pid_t pid)
537 {
538 struct proc_rlimit_control_wakeupmon params;
539
540 params.wm_flags = WAKEMON_ENABLE | WAKEMON_SET_DEFAULTS;
541 params.wm_rate = -1;
542
543 return (proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params));
544 }
545
546 int
547 proc_disable_wakemon(pid_t pid)
548 {
549 struct proc_rlimit_control_wakeupmon params;
550
551 params.wm_flags = WAKEMON_DISABLE;
552 params.wm_rate = -1;
553
554 return (proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params));
555 }
556
557 int
558 proc_list_uptrs(int pid, uint64_t *buf, uint32_t bufsz)
559 {
560 int i, j;
561 int nfds, nkns;
562 int count = 0;
563 int knote_max = 4096; /* arbitrary starting point */
564
565 /* if buffer is empty, this call simply counts the knotes */
566 if (bufsz > 0 && buf == NULL) {
567 errno = EFAULT;
568 return -1;
569 }
570
571 /* get the list of FDs for this process */
572 struct proc_fdinfo fdlist[OPEN_MAX+1];
573 nfds = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, &fdlist[1], OPEN_MAX*sizeof(struct proc_fdinfo));
574 if (nfds < 0 || nfds > OPEN_MAX) {
575 return -1;
576 }
577
578 /* Add FD -1, the implicit workq kqueue */
579 fdlist[0].proc_fd = -1;
580 fdlist[0].proc_fdtype = PROX_FDTYPE_KQUEUE;
581 nfds++;
582
583 struct kevent_extinfo *kqext = malloc(knote_max * sizeof(struct kevent_extinfo));
584 if (!kqext) {
585 errno = ENOMEM;
586 return -1;
587 }
588
589 for (i = 0; i < nfds; i++) {
590 if (fdlist[i].proc_fdtype != PROX_FDTYPE_KQUEUE) {
591 continue;
592 }
593
594 again:
595 nkns = __proc_info(PROC_INFO_CALL_PIDFDINFO, pid, PROC_PIDFDKQUEUE_EXTINFO,
596 (uint64_t)fdlist[i].proc_fd, kqext, knote_max * sizeof(struct kevent_extinfo));
597 if (nkns < 0) {
598 if (errno == EBADF) {
599 /* the FD table can change after enumerating the FDs */
600 errno = EAGAIN;
601 }
602 free(kqext);
603 return -1;
604 }
605
606 if (nkns > knote_max) {
607 /* there are more knotes than we requested - try again with a
608 * larger buffer */
609 free(kqext);
610 knote_max = nkns + 32; /* small margin in case of extra knotes */
611 kqext = malloc(knote_max * sizeof(struct kevent_extinfo));
612 if (!kqext) {
613 errno = ENOMEM;
614 return -1;
615 }
616 goto again;
617 }
618
619 for (j = 0; j < nkns; j++) {
620 if (kqext[j].kqext_kev.udata == 0) {
621 continue;
622 }
623
624 if (bufsz >= sizeof(uint64_t)) {
625 *buf++ = kqext[j].kqext_kev.udata;
626 bufsz -= sizeof(uint64_t);
627 }
628 count++;
629 }
630 }
631
632 free(kqext);
633 return count;
634 }
635
636 int
637 proc_setcpu_percentage(pid_t pid, int action, int percentage)
638 {
639 proc_policy_cpuusage_attr_t attr;
640
641 bzero(&attr, sizeof(proc_policy_cpuusage_attr_t));
642 attr.ppattr_cpu_attr = action;
643 attr.ppattr_cpu_percentage = percentage;
644 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_RESOURCE_USAGE, PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, (uint64_t)0) != -1)
645 return(0);
646 else
647 return(errno);
648 }
649
650 int
651 proc_clear_cpulimits(pid_t pid)
652 {
653 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_RESTORE, PROC_POLICY_RESOURCE_USAGE, PROC_POLICY_RUSAGE_CPU, NULL, pid, (uint64_t)0) != -1)
654 return(0);
655 else
656 return(errno);
657 }
658
659
660
661 /* Donate importance to adaptive processes from this process */
662 int
663 proc_donate_importance_boost()
664 {
665 int rval;
666
667 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
668 PROC_POLICY_ACTION_SET,
669 PROC_POLICY_BOOST,
670 PROC_POLICY_IMP_DONATION,
671 NULL, getpid(), 0);
672
673 if (rval == 0)
674 return (0);
675 else
676 return (errno);
677 }
678
679 static __attribute__((noinline)) void
680 proc_importance_bad_assertion(char *reason) {
681 (void)reason;
682 }
683
684 /*
685 * Use the address of these variables as the token. This way, they can be
686 * printed in the debugger as useful names.
687 */
688 uint64_t important_boost_assertion_token = 0xfafafafafafafafa;
689 uint64_t normal_boost_assertion_token = 0xfbfbfbfbfbfbfbfb;
690 uint64_t non_boost_assertion_token = 0xfcfcfcfcfcfcfcfc;
691 uint64_t denap_boost_assertion_token = 0xfdfdfdfdfdfdfdfd;
692
693 /*
694 * Accept the boost on a message, or request another boost assertion
695 * if we have already accepted the implicit boost for this message.
696 *
697 * Returns EOVERFLOW if an attempt is made to take an extra assertion when not boosted.
698 *
699 * Returns EIO if the message was not a boosting message.
700 * TODO: Return a 'non-boost' token instead.
701 */
702 int
703 proc_importance_assertion_begin_with_msg(mach_msg_header_t *msg,
704 __unused mach_msg_trailer_t *trailer,
705 uint64_t *assertion_token)
706 {
707 int rval = 0;
708
709 if (assertion_token == NULL)
710 return (EINVAL);
711
712 #define LEGACYBOOSTMASK (MACH_MSGH_BITS_VOUCHER_MASK | MACH_MSGH_BITS_RAISEIMP)
713 #define LEGACYBOOSTED(m) (((m)->msgh_bits & LEGACYBOOSTMASK) == MACH_MSGH_BITS_RAISEIMP)
714
715 /* Is this a legacy boosted message? */
716 if (LEGACYBOOSTED(msg)) {
717
718 /*
719 * Have we accepted the implicit boost for this message yet?
720 * If we haven't accepted it yet, no need to call into kernel.
721 */
722 if ((msg->msgh_bits & MACH_MSGH_BITS_IMPHOLDASRT) == 0) {
723 msg->msgh_bits |= MACH_MSGH_BITS_IMPHOLDASRT;
724 *assertion_token = (uint64_t) &important_boost_assertion_token;
725 return (0);
726 }
727
728 /* Request an additional boost count */
729 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
730 PROC_POLICY_ACTION_HOLD,
731 PROC_POLICY_BOOST,
732 PROC_POLICY_IMP_IMPORTANT,
733 NULL, getpid(), 0);
734 if (rval == 0) {
735 *assertion_token = (uint64_t) &important_boost_assertion_token;
736 return (0);
737 } else if (errno == EOVERFLOW) {
738 proc_importance_bad_assertion("Attempted to take assertion while not boosted");
739 return (errno);
740 } else {
741 return (errno);
742 }
743 }
744
745 return (EIO);
746 }
747
748
749 /*
750 * Drop a boost assertion.
751 * Returns EOVERFLOW on boost assertion underflow.
752 */
753 int
754 proc_importance_assertion_complete(uint64_t assertion_token)
755 {
756 int rval = 0;
757
758 if (assertion_token == 0)
759 return (0);
760
761 if (assertion_token == (uint64_t) &important_boost_assertion_token) {
762 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
763 PROC_POLICY_ACTION_DROP,
764 PROC_POLICY_BOOST,
765 PROC_POLICY_IMP_IMPORTANT,
766 NULL, getpid(), 0);
767 if (rval == 0) {
768 return (0);
769 } else if (errno == EOVERFLOW) {
770 proc_importance_bad_assertion("Attempted to drop too many assertions");
771 return (errno);
772 } else {
773 return (errno);
774 }
775 } else {
776 proc_importance_bad_assertion("Attempted to drop assertion with invalid token");
777 return (EIO);
778 }
779 }
780
781 /*
782 * Accept the De-Nap boost on a message, or request another boost assertion
783 * if we have already accepted the implicit boost for this message.
784 *
785 * Interface is deprecated before it really got started - just as synonym
786 * for proc_importance_assertion_begin_with_msg() now.
787 */
788 int
789 proc_denap_assertion_begin_with_msg(mach_msg_header_t *msg,
790 uint64_t *assertion_token)
791 {
792 #pragma clang diagnostic push
793 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
794 return proc_importance_assertion_begin_with_msg(msg, NULL, assertion_token);
795 #pragma clang diagnostic pop
796 }
797
798
799 /*
800 * Drop a denap boost assertion.
801 *
802 * Interface is deprecated before it really got started - just a synonym
803 * for proc_importance_assertion_complete() now.
804 */
805 int
806 proc_denap_assertion_complete(uint64_t assertion_token)
807 {
808 return proc_importance_assertion_complete(assertion_token);
809 }
810
811
812 int
813 proc_clear_vmpressure(pid_t pid)
814 {
815 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_RESTORE, PROC_POLICY_RESOURCE_STARVATION, PROC_POLICY_RS_VIRTUALMEM, NULL, pid, (uint64_t)0) != -1)
816 return(0);
817 else
818 return(errno);
819 }
820
821 /* set the current process as one who can resume suspended processes due to low virtual memory. Need to be root */
822 int
823 proc_set_owner_vmpressure(void)
824 {
825 int retval;
826
827 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_VMRSRCOWNER, (uint64_t)0, NULL, 0)) == -1)
828 return(errno);
829
830 return(0);
831 }
832
833 /* mark yourself to delay idle sleep on disk IO */
834 int
835 proc_set_delayidlesleep(void)
836 {
837 int retval;
838
839 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_DELAYIDLESLEEP, (uint64_t)1, NULL, 0)) == -1)
840 return(errno);
841
842 return(0);
843 }
844
845 /* Reset yourself to delay idle sleep on disk IO, if already set */
846 int
847 proc_clear_delayidlesleep(void)
848 {
849 int retval;
850
851 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_DELAYIDLESLEEP, (uint64_t)0, NULL, 0)) == -1)
852 return(errno);
853
854 return(0);
855 }
856
857 /* disable the launch time backgroudn policy and restore the process to default group */
858 int
859 proc_disable_apptype(pid_t pid, int apptype)
860 {
861 switch (apptype) {
862 case PROC_POLICY_OSX_APPTYPE_TAL:
863 case PROC_POLICY_OSX_APPTYPE_DASHCLIENT:
864 break;
865 default:
866 return(EINVAL);
867 }
868
869 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_DISABLE, PROC_POLICY_APPTYPE, apptype, NULL, pid, (uint64_t)0) != -1)
870 return(0);
871 else
872 return(errno);
873
874 }
875
876 /* re-enable the launch time background policy if it had been disabled. */
877 int
878 proc_enable_apptype(pid_t pid, int apptype)
879 {
880 switch (apptype) {
881 case PROC_POLICY_OSX_APPTYPE_TAL:
882 case PROC_POLICY_OSX_APPTYPE_DASHCLIENT:
883 break;
884 default:
885 return(EINVAL);
886
887 }
888
889 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_ENABLE, PROC_POLICY_APPTYPE, apptype, NULL, pid, (uint64_t)0) != -1)
890 return(0);
891 else
892 return(errno);
893
894 }
895
896 #if !TARGET_IPHONE_SIMULATOR
897
898 int
899 proc_suppress(__unused pid_t pid, __unused uint64_t *generation)
900 {
901 return 0;
902 }
903
904 #endif /* !TARGET_IPHONE_SIMULATOR */
905
906
907
908