2 * Copyright (c) 2006, 2010 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 #include <sys/cdefs.h>
29 #include <sys/errno.h>
30 #include <sys/msgbuf.h>
31 #include <sys/resource.h>
32 #define BUILD_LIBSYSCALL 1
33 #include <sys/process_policy.h>
34 #include <mach/message.h>
36 #include "libproc_internal.h"
38 int __proc_info(int callnum
, int pid
, int flavor
, uint64_t arg
, void * buffer
, int buffersize
);
39 __private_extern__
int proc_setthreadname(void * buffer
, int buffersize
);
40 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
);
41 int proc_rlimit_control(pid_t pid
, int flavor
, void *arg
);
44 proc_listpids(uint32_t type
, uint32_t typeinfo
, void *buffer
, int buffersize
)
48 if ((type
>= PROC_ALL_PIDS
) || (type
<= PROC_PPID_ONLY
)) {
49 if ((retval
= __proc_info(PROC_INFO_CALL_LISTPIDS
, type
, typeinfo
,(uint64_t)0, buffer
, buffersize
)) == -1)
60 proc_listallpids(void * buffer
, int buffersize
)
63 numpids
= proc_listpids(PROC_ALL_PIDS
, (uint32_t)0, buffer
, buffersize
);
68 return(numpids
/sizeof(int));
72 proc_listpgrppids(pid_t pgrpid
, void * buffer
, int buffersize
)
75 numpids
= proc_listpids(PROC_PGRP_ONLY
, (uint32_t)pgrpid
, buffer
, buffersize
);
79 return(numpids
/sizeof(int));
83 proc_listchildpids(pid_t ppid
, void * buffer
, int buffersize
)
86 numpids
= proc_listpids(PROC_PPID_ONLY
, (uint32_t)ppid
, buffer
, buffersize
);
90 return(numpids
/sizeof(int));
95 proc_pidinfo(int pid
, int flavor
, uint64_t arg
, void *buffer
, int buffersize
)
99 if ((retval
= __proc_info(PROC_INFO_CALL_PIDINFO
, pid
, flavor
, arg
, buffer
, buffersize
)) == -1)
106 proc_pid_rusage(int pid
, int flavor
, rusage_info_t
*buffer
)
108 return (__proc_info(PROC_INFO_CALL_PIDRUSAGE
, pid
, flavor
, 0, buffer
, 0));
112 proc_pidfdinfo(int pid
, int fd
, int flavor
, void * buffer
, int buffersize
)
116 if ((retval
= __proc_info(PROC_INFO_CALL_PIDFDINFO
, pid
, flavor
, (uint64_t)fd
, buffer
, buffersize
)) == -1)
124 proc_pidfileportinfo(int pid
, uint32_t fileport
, int flavor
, void *buffer
, int buffersize
)
128 if ((retval
= __proc_info(PROC_INFO_CALL_PIDFILEPORTINFO
, pid
, flavor
, (uint64_t)fileport
, buffer
, buffersize
)) == -1)
135 proc_name(int pid
, void * buffer
, uint32_t buffersize
)
138 struct proc_bsdinfo pbsd
;
141 if (buffersize
< sizeof(pbsd
.pbi_name
)) {
146 retval
= proc_pidinfo(pid
, PROC_PIDTBSDINFO
, (uint64_t)0, &pbsd
, sizeof(struct proc_bsdinfo
));
148 if (pbsd
.pbi_name
[0]) {
149 bcopy(&pbsd
.pbi_name
, buffer
, sizeof(pbsd
.pbi_name
));
151 bcopy(&pbsd
.pbi_comm
, buffer
, sizeof(pbsd
.pbi_comm
));
153 len
= strlen(buffer
);
160 proc_regionfilename(int pid
, uint64_t address
, void * buffer
, uint32_t buffersize
)
163 struct proc_regionwithpathinfo reginfo
;
165 if (buffersize
< MAXPATHLEN
) {
170 retval
= proc_pidinfo(pid
, PROC_PIDREGIONPATHINFO
, (uint64_t)address
, ®info
, sizeof(struct proc_regionwithpathinfo
));
172 len
= strlen(®info
.prp_vip
.vip_path
[0]);
174 if (len
> MAXPATHLEN
)
176 bcopy(®info
.prp_vip
.vip_path
[0], buffer
, len
);
186 proc_kmsgbuf(void * buffer
, uint32_t buffersize
)
190 if ((retval
= __proc_info(PROC_INFO_CALL_KERNMSGBUF
, 0, 0, (uint64_t)0, buffer
, buffersize
)) == -1)
196 proc_pidpath(int pid
, void * buffer
, uint32_t buffersize
)
200 if (buffersize
< PROC_PIDPATHINFO_SIZE
) {
204 if (buffersize
> PROC_PIDPATHINFO_MAXSIZE
) {
209 retval
= __proc_info(PROC_INFO_CALL_PIDINFO
, pid
, PROC_PIDPATHINFO
, (uint64_t)0, buffer
, buffersize
);
211 len
= strlen(buffer
);
219 proc_libversion(int *major
, int * minor
)
230 proc_setpcontrol(const int control
)
234 if (control
< PROC_SETPC_NONE
|| control
> PROC_SETPC_TERMINATE
)
237 if ((retval
= __proc_info(PROC_INFO_CALL_SETCONTROL
, getpid(), PROC_SELFSET_PCONTROL
, (uint64_t)control
, NULL
, 0)) == -1)
244 __private_extern__
int
245 proc_setthreadname(void * buffer
, int buffersize
)
249 retval
= __proc_info(PROC_INFO_CALL_SETCONTROL
, getpid(), PROC_SELFSET_THREADNAME
, (uint64_t)0, buffer
, buffersize
);
258 proc_track_dirty(pid_t pid
, uint32_t flags
)
260 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL
, pid
, PROC_DIRTYCONTROL_TRACK
, flags
, NULL
, 0) == -1) {
268 proc_set_dirty(pid_t pid
, bool dirty
)
270 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL
, pid
, PROC_DIRTYCONTROL_SET
, dirty
, NULL
, 0) == -1) {
278 proc_get_dirty(pid_t pid
, uint32_t *flags
)
286 retval
= __proc_info(PROC_INFO_CALL_DIRTYCONTROL
, pid
, PROC_DIRTYCONTROL_GET
, 0, NULL
, 0);
297 proc_terminate(pid_t pid
, int *sig
)
305 retval
= __proc_info(PROC_INFO_CALL_TERMINATE
, pid
, 0, 0, NULL
, 0);
316 proc_set_cpumon_params(pid_t pid
, int percentage
, int interval
)
318 proc_policy_cpuusage_attr_t attr
;
320 attr
.ppattr_cpu_attr
= PROC_POLICY_RSRCACT_NOTIFY_EXC
;
321 attr
.ppattr_cpu_percentage
= percentage
;
322 attr
.ppattr_cpu_attr_interval
= (uint64_t)interval
;
323 attr
.ppattr_cpu_attr_deadline
= 0;
325 return(__process_policy(PROC_POLICY_SCOPE_PROCESS
, PROC_POLICY_ACTION_SET
, PROC_POLICY_RESOURCE_USAGE
,
326 PROC_POLICY_RUSAGE_CPU
, (proc_policy_attribute_t
*)&attr
, pid
, 0));
330 proc_get_cpumon_params(pid_t pid
, int *percentage
, int *interval
)
332 proc_policy_cpuusage_attr_t attr
;
335 ret
= __process_policy(PROC_POLICY_SCOPE_PROCESS
, PROC_POLICY_ACTION_GET
, PROC_POLICY_RESOURCE_USAGE
,
336 PROC_POLICY_RUSAGE_CPU
, (proc_policy_attribute_t
*)&attr
, pid
, 0);
338 if ((ret
== 0) && (attr
.ppattr_cpu_attr
== PROC_POLICY_RSRCACT_NOTIFY_EXC
)) {
339 *percentage
= attr
.ppattr_cpu_percentage
;
340 *interval
= attr
.ppattr_cpu_attr_interval
;
350 proc_set_cpumon_defaults(pid_t pid
)
352 proc_policy_cpuusage_attr_t attr
;
354 attr
.ppattr_cpu_attr
= PROC_POLICY_RSRCACT_NOTIFY_EXC
;
355 attr
.ppattr_cpu_percentage
= PROC_POLICY_CPUMON_DEFAULTS
;
356 attr
.ppattr_cpu_attr_interval
= 0;
357 attr
.ppattr_cpu_attr_deadline
= 0;
359 return(__process_policy(PROC_POLICY_SCOPE_PROCESS
, PROC_POLICY_ACTION_SET
, PROC_POLICY_RESOURCE_USAGE
,
360 PROC_POLICY_RUSAGE_CPU
, (proc_policy_attribute_t
*)&attr
, pid
, 0));
364 proc_disable_cpumon(pid_t pid
)
366 proc_policy_cpuusage_attr_t attr
;
368 attr
.ppattr_cpu_attr
= PROC_POLICY_RSRCACT_NOTIFY_EXC
;
369 attr
.ppattr_cpu_percentage
= PROC_POLICY_CPUMON_DISABLE
;
370 attr
.ppattr_cpu_attr_interval
= 0;
371 attr
.ppattr_cpu_attr_deadline
= 0;
373 return(__process_policy(PROC_POLICY_SCOPE_PROCESS
, PROC_POLICY_ACTION_SET
, PROC_POLICY_RESOURCE_USAGE
,
374 PROC_POLICY_RUSAGE_CPU
, (proc_policy_attribute_t
*)&attr
, pid
, 0));
378 proc_set_wakemon_params(pid_t pid
, int rate_hz
, int flags __unused
)
380 struct proc_rlimit_control_wakeupmon params
;
382 params
.wm_flags
= WAKEMON_ENABLE
;
383 params
.wm_rate
= rate_hz
;
385 return (proc_rlimit_control(pid
, RLIMIT_WAKEUPS_MONITOR
, ¶ms
));
388 #ifndef WAKEMON_GET_PARAMS
389 #define WAKEMON_GET_PARAMS 0x4
390 #define WAKEMON_SET_DEFAULTS 0x8
394 proc_get_wakemon_params(pid_t pid
, int *rate_hz
, int *flags
)
396 struct proc_rlimit_control_wakeupmon params
;
399 params
.wm_flags
= WAKEMON_GET_PARAMS
;
401 if ((error
= proc_rlimit_control(pid
, RLIMIT_WAKEUPS_MONITOR
, ¶ms
)) != 0) {
405 *rate_hz
= params
.wm_rate
;
406 *flags
= params
.wm_flags
;
412 proc_set_wakemon_defaults(pid_t pid
)
414 struct proc_rlimit_control_wakeupmon params
;
416 params
.wm_flags
= WAKEMON_ENABLE
| WAKEMON_SET_DEFAULTS
;
419 return (proc_rlimit_control(pid
, RLIMIT_WAKEUPS_MONITOR
, ¶ms
));
423 proc_disable_wakemon(pid_t pid
)
425 struct proc_rlimit_control_wakeupmon params
;
427 params
.wm_flags
= WAKEMON_DISABLE
;
430 return (proc_rlimit_control(pid
, RLIMIT_WAKEUPS_MONITOR
, ¶ms
));
434 #if TARGET_OS_EMBEDDED
437 proc_setcpu_percentage(pid_t pid
, int action
, int percentage
)
439 proc_policy_cpuusage_attr_t attr
;
441 bzero(&attr
, sizeof(proc_policy_cpuusage_attr_t
));
442 attr
.ppattr_cpu_attr
= action
;
443 attr
.ppattr_cpu_percentage
= percentage
;
444 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)
451 proc_setcpu_deadline(pid_t pid
, int action
, uint64_t deadline
)
453 proc_policy_cpuusage_attr_t attr
;
455 bzero(&attr
, sizeof(proc_policy_cpuusage_attr_t
));
456 attr
.ppattr_cpu_attr
= action
;
457 attr
.ppattr_cpu_attr_deadline
= deadline
;
458 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)
467 proc_setcpu_percentage_withdeadline(pid_t pid
, int action
, int percentage
, uint64_t deadline
)
469 proc_policy_cpuusage_attr_t attr
;
471 bzero(&attr
, sizeof(proc_policy_cpuusage_attr_t
));
472 attr
.ppattr_cpu_attr
= action
;
473 attr
.ppattr_cpu_percentage
= percentage
;
474 attr
.ppattr_cpu_attr_deadline
= deadline
;
475 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)
482 proc_clear_cpulimits(pid_t pid
)
484 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)
493 proc_appstate(int pid
, int * appstatep
)
497 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) {
498 if (appstatep
!= NULL
)
508 proc_setappstate(int pid
, int appstate
)
510 int state
= appstate
;
513 case PROC_APPSTATE_NONE
:
514 case PROC_APPSTATE_ACTIVE
:
515 case PROC_APPSTATE_INACTIVE
:
516 case PROC_APPSTATE_BACKGROUND
:
517 case PROC_APPSTATE_NONUI
:
522 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)
529 proc_devstatusnotify(int devicestatus
)
531 int state
= devicestatus
;
533 switch (devicestatus
) {
534 case PROC_DEVSTATUS_SHORTTERM
:
535 case PROC_DEVSTATUS_LONGTERM
:
541 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) {
549 proc_pidbind(int pid
, uint64_t threadid
, int bind
)
555 case PROC_PIDBIND_CLEAR
:
556 passpid
= getpid(); /* ignore pid on clear */
558 case PROC_PIDBIND_SET
:
563 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)
568 #endif /* TARGET_OS_EMBEDDED */
571 /* Donate importance to adaptive processes from this process */
573 proc_donate_importance_boost()
577 #if TARGET_OS_EMBEDDED
578 rval
= __process_policy(PROC_POLICY_SCOPE_PROCESS
,
579 PROC_POLICY_ACTION_ENABLE
,
581 PROC_POLICY_IOS_DONATEIMP
,
582 NULL
, getpid(), (uint64_t)0);
583 #else /* TARGET_OS_EMBEDDED */
584 rval
= __process_policy(PROC_POLICY_SCOPE_PROCESS
,
585 PROC_POLICY_ACTION_SET
,
587 PROC_POLICY_IMP_DONATION
,
589 #endif /* TARGET_OS_EMBEDDED */
597 static __attribute__((noinline
)) void
598 proc_importance_bad_assertion(char *reason
) {
603 * Use the address of these variables as the token. This way, they can be
604 * printed in the debugger as useful names.
606 uint64_t important_boost_assertion_token
= 0xfafafafafafafafa;
607 uint64_t normal_boost_assertion_token
= 0xfbfbfbfbfbfbfbfb;
608 uint64_t non_boost_assertion_token
= 0xfcfcfcfcfcfcfcfc;
611 * Accept the boost on a message, or request another boost assertion
612 * if we have already accepted the implicit boost for this message.
614 * Returns EOVERFLOW if an attempt is made to take an extra assertion when not boosted.
616 * Returns EIO if the message was not a boosting message.
617 * TODO: Return a 'non-boost' token instead.
620 proc_importance_assertion_begin_with_msg(mach_msg_header_t
*msg
,
621 __unused mach_msg_trailer_t
*trailer
,
622 uint64_t *assertion_token
)
626 if (assertion_token
== NULL
)
629 /* Is this a boosting message? */
630 if ((msg
->msgh_bits
& MACH_MSGH_BITS_RAISEIMP
) != 0) {
633 * Have we accepted the implicit boost for this message yet?
634 * If we haven't accepted it yet, no need to call into kernel.
636 if ((msg
->msgh_bits
& MACH_MSGH_BITS_IMPHOLDASRT
) == 0) {
637 msg
->msgh_bits
|= MACH_MSGH_BITS_IMPHOLDASRT
;
638 *assertion_token
= (uint64_t) &important_boost_assertion_token
;
642 /* Request an additional boost count */
644 #if TARGET_OS_EMBEDDED
645 rval
= __process_policy(PROC_POLICY_SCOPE_PROCESS
,
646 PROC_POLICY_ACTION_ENABLE
,
648 PROC_POLICY_IOS_HOLDIMP
,
650 #else /* TARGET_OS_EMBEDDED */
651 rval
= __process_policy(PROC_POLICY_SCOPE_PROCESS
,
652 PROC_POLICY_ACTION_HOLD
,
654 PROC_POLICY_IMP_IMPORTANT
,
656 #endif /* TARGET_OS_EMBEDDED */
659 *assertion_token
= (uint64_t) &important_boost_assertion_token
;
661 } else if (errno
== EOVERFLOW
) {
662 proc_importance_bad_assertion("Attempted to take assertion while not boosted");
674 * Drop a boost assertion.
675 * Returns EOVERFLOW on boost assertion underflow.
678 proc_importance_assertion_complete(uint64_t assertion_token
)
682 if (assertion_token
== 0)
685 if (assertion_token
== (uint64_t) &important_boost_assertion_token
) {
687 #if TARGET_OS_EMBEDDED
688 rval
= __process_policy(PROC_POLICY_SCOPE_PROCESS
,
689 PROC_POLICY_ACTION_ENABLE
,
691 PROC_POLICY_IOS_DROPIMP
,
693 #else /* TARGET_OS_EMBEDDED */
694 rval
= __process_policy(PROC_POLICY_SCOPE_PROCESS
,
695 PROC_POLICY_ACTION_DROP
,
697 PROC_POLICY_IMP_IMPORTANT
,
699 #endif /* TARGET_OS_EMBEDDED */
703 } else if (errno
== EOVERFLOW
) {
704 proc_importance_bad_assertion("Attempted to drop too many assertions");
710 proc_importance_bad_assertion("Attempted to drop assertion with invalid token");
715 #if !TARGET_OS_EMBEDDED
718 proc_clear_vmpressure(pid_t pid
)
720 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)
726 /* set the current process as one who can resume suspended processes due to low virtual memory. Need to be root */
728 proc_set_owner_vmpressure(void)
732 if ((retval
= __proc_info(PROC_INFO_CALL_SETCONTROL
, getpid(), PROC_SELFSET_VMRSRCOWNER
, (uint64_t)0, NULL
, 0)) == -1)
738 /* mark yourself to delay idle sleep on disk IO */
740 proc_set_delayidlesleep(void)
744 if ((retval
= __proc_info(PROC_INFO_CALL_SETCONTROL
, getpid(), PROC_SELFSET_DELAYIDLESLEEP
, (uint64_t)1, NULL
, 0)) == -1)
750 /* Reset yourself to delay idle sleep on disk IO, if already set */
752 proc_clear_delayidlesleep(void)
756 if ((retval
= __proc_info(PROC_INFO_CALL_SETCONTROL
, getpid(), PROC_SELFSET_DELAYIDLESLEEP
, (uint64_t)0, NULL
, 0)) == -1)
762 /* disable the launch time backgroudn policy and restore the process to default group */
764 proc_disable_apptype(pid_t pid
, int apptype
)
767 case PROC_POLICY_OSX_APPTYPE_TAL
:
768 case PROC_POLICY_OSX_APPTYPE_DASHCLIENT
:
774 if (__process_policy(PROC_POLICY_SCOPE_PROCESS
, PROC_POLICY_ACTION_DISABLE
, PROC_POLICY_APPTYPE
, apptype
, NULL
, pid
, (uint64_t)0) != -1)
781 /* re-enable the launch time background policy if it had been disabled. */
783 proc_enable_apptype(pid_t pid
, int apptype
)
786 case PROC_POLICY_OSX_APPTYPE_TAL
:
787 case PROC_POLICY_OSX_APPTYPE_DASHCLIENT
:
794 if (__process_policy(PROC_POLICY_SCOPE_PROCESS
, PROC_POLICY_ACTION_ENABLE
, PROC_POLICY_APPTYPE
, apptype
, NULL
, pid
, (uint64_t)0) != -1)
801 #if !TARGET_IPHONE_SIMULATOR
804 proc_suppress(__unused pid_t pid
, __unused
uint64_t *generation
)
809 #endif /* !TARGET_IPHONE_SIMULATOR */
811 #endif /* !TARGET_OS_EMBEDDED */