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