]> git.saurik.com Git - apple/xnu.git/blame - libsyscall/wrappers/libproc/libproc.c
xnu-3789.70.16.tar.gz
[apple/xnu.git] / libsyscall / wrappers / libproc / libproc.c
CommitLineData
39236c6e
A
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>
3e170ce0 29#include <stdlib.h>
39236c6e
A
30#include <sys/errno.h>
31#include <sys/msgbuf.h>
32#include <sys/resource.h>
39236c6e 33#include <sys/process_policy.h>
3e170ce0 34#include <sys/event.h>
39236c6e
A
35#include <mach/message.h>
36
37#include "libproc_internal.h"
38
39int __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);
41int __process_policy(int scope, int action, int policy, int policy_subtype, proc_policy_attribute_t * attrp, pid_t target_pid, uint64_t target_threadid);
42int proc_rlimit_control(pid_t pid, int flavor, void *arg);
43
44int
45proc_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
60int
61proc_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
72int
73proc_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
83int
84proc_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
95int
96proc_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
fe8ab488
A
106
107int
108proc_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
3e170ce0
A
118int
119proc_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
39236c6e
A
129int
130proc_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
fe8ab488
A
135int
136proc_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
39236c6e
A
151int
152proc_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
163int
164proc_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
174int
175proc_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 }
fe8ab488 193 len = (int)strlen(buffer);
39236c6e
A
194 return(len);
195 }
196 return(0);
197}
198
199int
200proc_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) {
fe8ab488 212 len = (int)strlen(&reginfo.prp_vip.vip_path[0]);
39236c6e
A
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
225int
226proc_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
235int
236proc_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) {
fe8ab488 251 len = (int)strlen(buffer);
39236c6e
A
252 return(len);
253 }
254 return (0);
255}
256
257
258int
259proc_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
269int
270proc_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
285proc_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
297int
298proc_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
307int
308proc_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
317int
318proc_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
fe8ab488
A
336int
337proc_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
39236c6e
A
346int
347proc_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
39037602
A
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 */
39236c6e
A
370int
371proc_set_cpumon_params(pid_t pid, int percentage, int interval)
372{
373 proc_policy_cpuusage_attr_t attr;
374
39037602
A
375 /* no argument validation ...
376 * task_set_cpuusage() ignores 0 values and squashes negative
377 * values into uint32_t.
378 */
379
39236c6e
A
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
389int
390proc_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;
fe8ab488 400 *interval = (int)attr.ppattr_cpu_attr_interval;
39236c6e
A
401 } else {
402 *percentage = 0;
403 *interval = 0;
404 }
405
406 return (ret);
407}
408
409int
410proc_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
39037602
A
423int
424proc_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
39236c6e
A
433int
434proc_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
fe8ab488
A
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 */
455int
456proc_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.
39037602
A
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.
fe8ab488
A
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
39236c6e
A
501int
502proc_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
517int
518proc_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
535int
536proc_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
546int
547proc_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
3e170ce0
A
557int
558proc_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
39037602
A
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) {
3e170ce0
A
575 return -1;
576 }
577
39037602
A
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
3e170ce0
A
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}
39236c6e 635
d190cdc3
A
636int
637proc_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
650int
651proc_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
39236c6e
A
659
660
661/* Donate importance to adaptive processes from this process */
662int
663proc_donate_importance_boost()
664{
665 int rval;
666
39236c6e
A
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);
39236c6e
A
672
673 if (rval == 0)
674 return (0);
675 else
676 return (errno);
677}
678
679static __attribute__((noinline)) void
680proc_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 */
688uint64_t important_boost_assertion_token = 0xfafafafafafafafa;
689uint64_t normal_boost_assertion_token = 0xfbfbfbfbfbfbfbfb;
690uint64_t non_boost_assertion_token = 0xfcfcfcfcfcfcfcfc;
fe8ab488 691uint64_t denap_boost_assertion_token = 0xfdfdfdfdfdfdfdfd;
39236c6e
A
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 */
702int
703proc_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);
fe8ab488
A
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)) {
39236c6e
A
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 */
39236c6e
A
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);
39236c6e
A
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 */
753int
754proc_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) {
39236c6e
A
762 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
763 PROC_POLICY_ACTION_DROP,
764 PROC_POLICY_BOOST,
765 PROC_POLICY_IMP_IMPORTANT,
fe8ab488 766 NULL, getpid(), 0);
39236c6e
A
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
fe8ab488
A
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 */
788int
789proc_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 */
805int
806proc_denap_assertion_complete(uint64_t assertion_token)
807{
808 return proc_importance_assertion_complete(assertion_token);
809}
810
39236c6e
A
811
812int
813proc_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 */
822int
823proc_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 */
834int
835proc_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 */
846int
847proc_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 */
858int
859proc_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. */
877int
878proc_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
898int
899proc_suppress(__unused pid_t pid, __unused uint64_t *generation)
900{
901 return 0;
902}
903
904#endif /* !TARGET_IPHONE_SIMULATOR */
905
39236c6e
A
906
907
908