]> git.saurik.com Git - apple/xnu.git/blob - libsyscall/wrappers/libproc/libproc.c
xnu-4570.31.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 int
174 proc_piddynkqueueinfo(int pid, int flavor, kqueue_id_t kq_id, void *buffer, int buffersize)
175 {
176 int ret;
177
178 if ((ret = __proc_info(PROC_INFO_CALL_PIDDYNKQUEUEINFO, pid, flavor, (uint64_t)kq_id, buffer, buffersize)) == -1) {
179 return 0;
180 }
181
182 return ret;
183 }
184
185 int
186 proc_name(int pid, void * buffer, uint32_t buffersize)
187 {
188 int retval = 0, len;
189 struct proc_bsdinfo pbsd;
190
191
192 if (buffersize < sizeof(pbsd.pbi_name)) {
193 errno = ENOMEM;
194 return(0);
195 }
196
197 retval = proc_pidinfo(pid, PROC_PIDTBSDINFO, (uint64_t)0, &pbsd, sizeof(struct proc_bsdinfo));
198 if (retval != 0) {
199 if (pbsd.pbi_name[0]) {
200 bcopy(&pbsd.pbi_name, buffer, sizeof(pbsd.pbi_name));
201 } else {
202 bcopy(&pbsd.pbi_comm, buffer, sizeof(pbsd.pbi_comm));
203 }
204 len = (int)strlen(buffer);
205 return(len);
206 }
207 return(0);
208 }
209
210 int
211 proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersize)
212 {
213 int retval;
214 struct proc_regionwithpathinfo reginfo;
215
216 if (buffersize < MAXPATHLEN) {
217 errno = ENOMEM;
218 return(0);
219 }
220
221 retval = proc_pidinfo(pid, PROC_PIDREGIONPATHINFO, (uint64_t)address, &reginfo, sizeof(struct proc_regionwithpathinfo));
222 if (retval != -1) {
223 return ((int)(strlcpy(buffer, reginfo.prp_vip.vip_path, MAXPATHLEN)));
224 }
225 return(0);
226 }
227
228 int
229 proc_kmsgbuf(void * buffer, uint32_t buffersize)
230 {
231 int retval;
232
233 if ((retval = __proc_info(PROC_INFO_CALL_KERNMSGBUF, 0, 0, (uint64_t)0, buffer, buffersize)) == -1)
234 return(0);
235 return (retval);
236 }
237
238 int
239 proc_pidpath(int pid, void * buffer, uint32_t buffersize)
240 {
241 int retval, len;
242
243 if (buffersize < PROC_PIDPATHINFO_SIZE) {
244 errno = ENOMEM;
245 return(0);
246 }
247 if (buffersize > PROC_PIDPATHINFO_MAXSIZE) {
248 errno = EOVERFLOW;
249 return(0);
250 }
251
252 retval = __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDPATHINFO, (uint64_t)0, buffer, buffersize);
253 if (retval != -1) {
254 len = (int)strlen(buffer);
255 return(len);
256 }
257 return (0);
258 }
259
260
261 int
262 proc_libversion(int *major, int * minor)
263 {
264
265 if (major != NULL)
266 *major = 1;
267 if (minor != NULL)
268 *minor = 1;
269 return(0);
270 }
271
272 int
273 proc_setpcontrol(const int control)
274 {
275 int retval ;
276
277 if (control < PROC_SETPC_NONE || control > PROC_SETPC_TERMINATE)
278 return(EINVAL);
279
280 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_PCONTROL, (uint64_t)control, NULL, 0)) == -1)
281 return(errno);
282
283 return(0);
284 }
285
286
287 __private_extern__ int
288 proc_setthreadname(void * buffer, int buffersize)
289 {
290 int retval;
291
292 retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_THREADNAME, (uint64_t)0, buffer, buffersize);
293
294 if (retval == -1)
295 return(errno);
296 else
297 return(0);
298 }
299
300 int
301 proc_track_dirty(pid_t pid, uint32_t flags)
302 {
303 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_TRACK, flags, NULL, 0) == -1) {
304 return errno;
305 }
306
307 return 0;
308 }
309
310 int
311 proc_set_dirty(pid_t pid, bool dirty)
312 {
313 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_SET, dirty, NULL, 0) == -1) {
314 return errno;
315 }
316
317 return 0;
318 }
319
320 int
321 proc_get_dirty(pid_t pid, uint32_t *flags)
322 {
323 int retval;
324
325 if (!flags) {
326 return EINVAL;
327 }
328
329 retval = __proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_GET, 0, NULL, 0);
330 if (retval == -1) {
331 return errno;
332 }
333
334 *flags = retval;
335
336 return 0;
337 }
338
339 int
340 proc_clear_dirty(pid_t pid, uint32_t flags)
341 {
342 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_CLEAR, flags, NULL, 0) == -1) {
343 return errno;
344 }
345
346 return 0;
347 }
348
349 int
350 proc_terminate(pid_t pid, int *sig)
351 {
352 int retval;
353
354 if (!sig) {
355 return EINVAL;
356 }
357
358 retval = __proc_info(PROC_INFO_CALL_TERMINATE, pid, 0, 0, NULL, 0);
359 if (retval == -1) {
360 return errno;
361 }
362
363 *sig = retval;
364
365 return 0;
366 }
367
368 /*
369 * XXX the _fatal() variant both checks for an existing monitor
370 * (with important policy effects on first party background apps)
371 * and validates inputs.
372 */
373 int
374 proc_set_cpumon_params(pid_t pid, int percentage, int interval)
375 {
376 proc_policy_cpuusage_attr_t attr;
377
378 /* no argument validation ...
379 * task_set_cpuusage() ignores 0 values and squashes negative
380 * values into uint32_t.
381 */
382
383 attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
384 attr.ppattr_cpu_percentage = percentage;
385 attr.ppattr_cpu_attr_interval = (uint64_t)interval;
386 attr.ppattr_cpu_attr_deadline = 0;
387
388 return(__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
389 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0));
390 }
391
392 int
393 proc_get_cpumon_params(pid_t pid, int *percentage, int *interval)
394 {
395 proc_policy_cpuusage_attr_t attr;
396 int ret;
397
398 ret = __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_GET, PROC_POLICY_RESOURCE_USAGE,
399 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
400
401 if ((ret == 0) && (attr.ppattr_cpu_attr == PROC_POLICY_RSRCACT_NOTIFY_EXC)) {
402 *percentage = attr.ppattr_cpu_percentage;
403 *interval = (int)attr.ppattr_cpu_attr_interval;
404 } else {
405 *percentage = 0;
406 *interval = 0;
407 }
408
409 return (ret);
410 }
411
412 int
413 proc_set_cpumon_defaults(pid_t pid)
414 {
415 proc_policy_cpuusage_attr_t attr;
416
417 attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
418 attr.ppattr_cpu_percentage = PROC_POLICY_CPUMON_DEFAULTS;
419 attr.ppattr_cpu_attr_interval = 0;
420 attr.ppattr_cpu_attr_deadline = 0;
421
422 return(__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
423 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0));
424 }
425
426 int
427 proc_resume_cpumon(pid_t pid)
428 {
429 return __process_policy(PROC_POLICY_SCOPE_PROCESS,
430 PROC_POLICY_ACTION_ENABLE,
431 PROC_POLICY_RESOURCE_USAGE,
432 PROC_POLICY_RUSAGE_CPU,
433 NULL, pid, 0);
434 }
435
436 int
437 proc_disable_cpumon(pid_t pid)
438 {
439 proc_policy_cpuusage_attr_t attr;
440
441 attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
442 attr.ppattr_cpu_percentage = PROC_POLICY_CPUMON_DISABLE;
443 attr.ppattr_cpu_attr_interval = 0;
444 attr.ppattr_cpu_attr_deadline = 0;
445
446 return(__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
447 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0));
448 }
449
450
451 /*
452 * Turn on the CPU usage monitor using the supplied parameters, and make
453 * violations of the monitor fatal.
454 *
455 * Returns: 0 on success;
456 * -1 on failure and sets errno
457 */
458 int
459 proc_set_cpumon_params_fatal(pid_t pid, int percentage, int interval)
460 {
461 int current_percentage = 0;
462 int current_interval = 0; /* intervals are in seconds */
463 int ret = 0;
464
465 if ((percentage <= 0) || (interval <= 0)) {
466 errno = EINVAL;
467 return (-1);
468 }
469
470 /*
471 * Do a simple query to see if CPU monitoring is
472 * already active. If either the percentage or the
473 * interval is nonzero, then CPU monitoring is
474 * already in use for this process.
475 *
476 * XXX: need set...() and set..fatal() to behave similarly.
477 * Currently, this check prevents 1st party apps (which get a
478 * default non-fatal monitor) not to get a fatal monitor.
479 */
480 (void)proc_get_cpumon_params(pid, &current_percentage, &current_interval);
481 if (current_percentage || current_interval)
482 {
483 /*
484 * The CPU monitor appears to be active.
485 * We choose not to disturb those settings.
486 */
487 errno = EBUSY;
488 return (-1);
489 }
490
491 if ((ret = proc_set_cpumon_params(pid, percentage, interval)) != 0) {
492 /* Failed to activate the CPU monitor */
493 return (ret);
494 }
495
496 if ((ret = proc_rlimit_control(pid, RLIMIT_CPU_USAGE_MONITOR, CPUMON_MAKE_FATAL)) != 0) {
497 /* Failed to set termination, back out the CPU monitor settings. */
498 (void)proc_disable_cpumon(pid);
499 }
500
501 return (ret);
502 }
503
504 int
505 proc_set_wakemon_params(pid_t pid, int rate_hz, int flags __unused)
506 {
507 struct proc_rlimit_control_wakeupmon params;
508
509 params.wm_flags = WAKEMON_ENABLE;
510 params.wm_rate = rate_hz;
511
512 return (proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params));
513 }
514
515 #ifndef WAKEMON_GET_PARAMS
516 #define WAKEMON_GET_PARAMS 0x4
517 #define WAKEMON_SET_DEFAULTS 0x8
518 #endif
519
520 int
521 proc_get_wakemon_params(pid_t pid, int *rate_hz, int *flags)
522 {
523 struct proc_rlimit_control_wakeupmon params;
524 int error;
525
526 params.wm_flags = WAKEMON_GET_PARAMS;
527
528 if ((error = proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params)) != 0) {
529 return (error);
530 }
531
532 *rate_hz = params.wm_rate;
533 *flags = params.wm_flags;
534
535 return (0);
536 }
537
538 int
539 proc_set_wakemon_defaults(pid_t pid)
540 {
541 struct proc_rlimit_control_wakeupmon params;
542
543 params.wm_flags = WAKEMON_ENABLE | WAKEMON_SET_DEFAULTS;
544 params.wm_rate = -1;
545
546 return (proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params));
547 }
548
549 int
550 proc_disable_wakemon(pid_t pid)
551 {
552 struct proc_rlimit_control_wakeupmon params;
553
554 params.wm_flags = WAKEMON_DISABLE;
555 params.wm_rate = -1;
556
557 return (proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params));
558 }
559
560 int
561 proc_list_uptrs(int pid, uint64_t *buf, uint32_t bufsz)
562 {
563 return __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDLISTUPTRS, 0,
564 buf, bufsz);
565 }
566
567 int
568 proc_list_dynkqueueids(int pid, kqueue_id_t *buf, uint32_t bufsz)
569 {
570 return __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDLISTDYNKQUEUES, 0,
571 buf, bufsz);
572 }
573
574
575 int
576 proc_setcpu_percentage(pid_t pid, int action, int percentage)
577 {
578 proc_policy_cpuusage_attr_t attr;
579
580 bzero(&attr, sizeof(proc_policy_cpuusage_attr_t));
581 attr.ppattr_cpu_attr = action;
582 attr.ppattr_cpu_percentage = percentage;
583 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)
584 return(0);
585 else
586 return(errno);
587 }
588
589 int
590 proc_clear_cpulimits(pid_t pid)
591 {
592 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)
593 return(0);
594 else
595 return(errno);
596 }
597
598 #if TARGET_OS_EMBEDDED
599
600 int
601 proc_setcpu_deadline(pid_t pid, int action, uint64_t deadline)
602 {
603 proc_policy_cpuusage_attr_t attr;
604
605 bzero(&attr, sizeof(proc_policy_cpuusage_attr_t));
606 attr.ppattr_cpu_attr = action;
607 attr.ppattr_cpu_attr_deadline = deadline;
608 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)
609 return(0);
610 else
611 return(errno);
612
613 }
614
615 int
616 proc_setcpu_percentage_withdeadline(pid_t pid, int action, int percentage, uint64_t deadline)
617 {
618 proc_policy_cpuusage_attr_t attr;
619
620 bzero(&attr, sizeof(proc_policy_cpuusage_attr_t));
621 attr.ppattr_cpu_attr = action;
622 attr.ppattr_cpu_percentage = percentage;
623 attr.ppattr_cpu_attr_deadline = deadline;
624 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)
625 return(0);
626 else
627 return(errno);
628 }
629
630 int
631 proc_appstate(int pid, int * appstatep)
632 {
633 int state;
634
635 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_GET, PROC_POLICY_APP_LIFECYCLE, PROC_POLICY_APPLIFE_STATE, (proc_policy_attribute_t*)&state, pid, (uint64_t)0) != -1) {
636 if (appstatep != NULL)
637 *appstatep = state;
638 return(0);
639 } else
640 return(errno);
641
642 }
643
644 int
645 proc_setappstate(int pid, int appstate)
646 {
647 int state = appstate;
648
649 switch (state) {
650 case PROC_APPSTATE_NONE:
651 case PROC_APPSTATE_ACTIVE:
652 case PROC_APPSTATE_INACTIVE:
653 case PROC_APPSTATE_BACKGROUND:
654 case PROC_APPSTATE_NONUI:
655 break;
656 default:
657 return(EINVAL);
658 }
659 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_APP_LIFECYCLE, PROC_POLICY_APPLIFE_STATE, (proc_policy_attribute_t*)&state, pid, (uint64_t)0) != -1)
660 return(0);
661 else
662 return(errno);
663 }
664
665 int
666 proc_devstatusnotify(int devicestatus)
667 {
668 int state = devicestatus;
669
670 switch (devicestatus) {
671 case PROC_DEVSTATUS_SHORTTERM:
672 case PROC_DEVSTATUS_LONGTERM:
673 break;
674 default:
675 return(EINVAL);
676 }
677
678 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_APP_LIFECYCLE, PROC_POLICY_APPLIFE_DEVSTATUS, (proc_policy_attribute_t*)&state, getpid(), (uint64_t)0) != -1) {
679 return(0);
680 } else
681 return(errno);
682
683 }
684
685 int
686 proc_pidbind(int pid, uint64_t threadid, int bind)
687 {
688 int state = bind;
689 pid_t passpid = pid;
690
691 switch (bind) {
692 case PROC_PIDBIND_CLEAR:
693 passpid = getpid(); /* ignore pid on clear */
694 break;
695 case PROC_PIDBIND_SET:
696 break;
697 default:
698 return(EINVAL);
699 }
700 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_APP_LIFECYCLE, PROC_POLICY_APPLIFE_PIDBIND, (proc_policy_attribute_t*)&state, passpid, threadid) != -1)
701 return(0);
702 else
703 return(errno);
704 }
705
706 int
707 proc_can_use_foreground_hw(int pid, uint32_t *reason)
708 {
709 return __proc_info(PROC_INFO_CALL_CANUSEFGHW, pid, 0, NULL, reason, sizeof(*reason));
710 }
711 #endif /* TARGET_OS_EMBEDDED */
712
713
714 /* Donate importance to adaptive processes from this process */
715 int
716 proc_donate_importance_boost()
717 {
718 int rval;
719
720 #if TARGET_OS_EMBEDDED
721 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
722 PROC_POLICY_ACTION_ENABLE,
723 PROC_POLICY_APPTYPE,
724 PROC_POLICY_IOS_DONATEIMP,
725 NULL, getpid(), (uint64_t)0);
726 #else /* TARGET_OS_EMBEDDED */
727 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
728 PROC_POLICY_ACTION_SET,
729 PROC_POLICY_BOOST,
730 PROC_POLICY_IMP_DONATION,
731 NULL, getpid(), 0);
732 #endif /* TARGET_OS_EMBEDDED */
733
734 if (rval == 0)
735 return (0);
736 else
737 return (errno);
738 }
739
740 static __attribute__((noinline)) void
741 proc_importance_bad_assertion(char *reason) {
742 (void)reason;
743 }
744
745 /*
746 * Use the address of these variables as the token. This way, they can be
747 * printed in the debugger as useful names.
748 */
749 uint64_t important_boost_assertion_token = 0xfafafafafafafafa;
750 uint64_t normal_boost_assertion_token = 0xfbfbfbfbfbfbfbfb;
751 uint64_t non_boost_assertion_token = 0xfcfcfcfcfcfcfcfc;
752 uint64_t denap_boost_assertion_token = 0xfdfdfdfdfdfdfdfd;
753
754 /*
755 * Accept the boost on a message, or request another boost assertion
756 * if we have already accepted the implicit boost for this message.
757 *
758 * Returns EOVERFLOW if an attempt is made to take an extra assertion when not boosted.
759 *
760 * Returns EIO if the message was not a boosting message.
761 * TODO: Return a 'non-boost' token instead.
762 */
763 int
764 proc_importance_assertion_begin_with_msg(mach_msg_header_t *msg,
765 __unused mach_msg_trailer_t *trailer,
766 uint64_t *assertion_token)
767 {
768 int rval = 0;
769
770 if (assertion_token == NULL)
771 return (EINVAL);
772
773 #define LEGACYBOOSTMASK (MACH_MSGH_BITS_VOUCHER_MASK | MACH_MSGH_BITS_RAISEIMP)
774 #define LEGACYBOOSTED(m) (((m)->msgh_bits & LEGACYBOOSTMASK) == MACH_MSGH_BITS_RAISEIMP)
775
776 /* Is this a legacy boosted message? */
777 if (LEGACYBOOSTED(msg)) {
778
779 /*
780 * Have we accepted the implicit boost for this message yet?
781 * If we haven't accepted it yet, no need to call into kernel.
782 */
783 if ((msg->msgh_bits & MACH_MSGH_BITS_IMPHOLDASRT) == 0) {
784 msg->msgh_bits |= MACH_MSGH_BITS_IMPHOLDASRT;
785 *assertion_token = (uint64_t) &important_boost_assertion_token;
786 return (0);
787 }
788
789 /* Request an additional boost count */
790 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
791 PROC_POLICY_ACTION_HOLD,
792 PROC_POLICY_BOOST,
793 PROC_POLICY_IMP_IMPORTANT,
794 NULL, getpid(), 0);
795 if (rval == 0) {
796 *assertion_token = (uint64_t) &important_boost_assertion_token;
797 return (0);
798 } else if (errno == EOVERFLOW) {
799 proc_importance_bad_assertion("Attempted to take assertion while not boosted");
800 return (errno);
801 } else {
802 return (errno);
803 }
804 }
805
806 return (EIO);
807 }
808
809
810 /*
811 * Drop a boost assertion.
812 * Returns EOVERFLOW on boost assertion underflow.
813 */
814 int
815 proc_importance_assertion_complete(uint64_t assertion_token)
816 {
817 int rval = 0;
818
819 if (assertion_token == 0)
820 return (0);
821
822 if (assertion_token == (uint64_t) &important_boost_assertion_token) {
823 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
824 PROC_POLICY_ACTION_DROP,
825 PROC_POLICY_BOOST,
826 PROC_POLICY_IMP_IMPORTANT,
827 NULL, getpid(), 0);
828 if (rval == 0) {
829 return (0);
830 } else if (errno == EOVERFLOW) {
831 proc_importance_bad_assertion("Attempted to drop too many assertions");
832 return (errno);
833 } else {
834 return (errno);
835 }
836 } else {
837 proc_importance_bad_assertion("Attempted to drop assertion with invalid token");
838 return (EIO);
839 }
840 }
841
842 /*
843 * Accept the De-Nap boost on a message, or request another boost assertion
844 * if we have already accepted the implicit boost for this message.
845 *
846 * Interface is deprecated before it really got started - just as synonym
847 * for proc_importance_assertion_begin_with_msg() now.
848 */
849 int
850 proc_denap_assertion_begin_with_msg(mach_msg_header_t *msg,
851 uint64_t *assertion_token)
852 {
853 #pragma clang diagnostic push
854 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
855 return proc_importance_assertion_begin_with_msg(msg, NULL, assertion_token);
856 #pragma clang diagnostic pop
857 }
858
859
860 /*
861 * Drop a denap boost assertion.
862 *
863 * Interface is deprecated before it really got started - just a synonym
864 * for proc_importance_assertion_complete() now.
865 */
866 int
867 proc_denap_assertion_complete(uint64_t assertion_token)
868 {
869 return proc_importance_assertion_complete(assertion_token);
870 }
871
872 #if !TARGET_OS_EMBEDDED
873
874 int
875 proc_clear_vmpressure(pid_t pid)
876 {
877 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)
878 return(0);
879 else
880 return(errno);
881 }
882
883 /* set the current process as one who can resume suspended processes due to low virtual memory. Need to be root */
884 int
885 proc_set_owner_vmpressure(void)
886 {
887 int retval;
888
889 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_VMRSRCOWNER, (uint64_t)0, NULL, 0)) == -1)
890 return(errno);
891
892 return(0);
893 }
894
895 /* mark yourself to delay idle sleep on disk IO */
896 int
897 proc_set_delayidlesleep(void)
898 {
899 int retval;
900
901 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_DELAYIDLESLEEP, (uint64_t)1, NULL, 0)) == -1)
902 return(errno);
903
904 return(0);
905 }
906
907 /* Reset yourself to delay idle sleep on disk IO, if already set */
908 int
909 proc_clear_delayidlesleep(void)
910 {
911 int retval;
912
913 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_DELAYIDLESLEEP, (uint64_t)0, NULL, 0)) == -1)
914 return(errno);
915
916 return(0);
917 }
918
919 /* disable the launch time backgroudn policy and restore the process to default group */
920 int
921 proc_disable_apptype(pid_t pid, int apptype)
922 {
923 switch (apptype) {
924 case PROC_POLICY_OSX_APPTYPE_TAL:
925 case PROC_POLICY_OSX_APPTYPE_DASHCLIENT:
926 break;
927 default:
928 return(EINVAL);
929 }
930
931 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_DISABLE, PROC_POLICY_APPTYPE, apptype, NULL, pid, (uint64_t)0) != -1)
932 return(0);
933 else
934 return(errno);
935
936 }
937
938 /* re-enable the launch time background policy if it had been disabled. */
939 int
940 proc_enable_apptype(pid_t pid, int apptype)
941 {
942 switch (apptype) {
943 case PROC_POLICY_OSX_APPTYPE_TAL:
944 case PROC_POLICY_OSX_APPTYPE_DASHCLIENT:
945 break;
946 default:
947 return(EINVAL);
948
949 }
950
951 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_ENABLE, PROC_POLICY_APPTYPE, apptype, NULL, pid, (uint64_t)0) != -1)
952 return(0);
953 else
954 return(errno);
955
956 }
957
958 #if !TARGET_IPHONE_SIMULATOR
959
960 int
961 proc_suppress(__unused pid_t pid, __unused uint64_t *generation)
962 {
963 return 0;
964 }
965
966 #endif /* !TARGET_IPHONE_SIMULATOR */
967
968 #endif /* !TARGET_OS_EMBEDDED */
969
970
971