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>
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>
37 #include "libproc_internal.h"
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
);
45 proc_listpids(uint32_t type
, uint32_t typeinfo
, void *buffer
, int buffersize
)
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)
61 proc_listallpids(void * buffer
, int buffersize
)
64 numpids
= proc_listpids(PROC_ALL_PIDS
, (uint32_t)0, buffer
, buffersize
);
69 return(numpids
/sizeof(int));
73 proc_listpgrppids(pid_t pgrpid
, void * buffer
, int buffersize
)
76 numpids
= proc_listpids(PROC_PGRP_ONLY
, (uint32_t)pgrpid
, buffer
, buffersize
);
80 return(numpids
/sizeof(int));
84 proc_listchildpids(pid_t ppid
, void * buffer
, int buffersize
)
87 numpids
= proc_listpids(PROC_PPID_ONLY
, (uint32_t)ppid
, buffer
, buffersize
);
91 return(numpids
/sizeof(int));
96 proc_pidinfo(int pid
, int flavor
, uint64_t arg
, void *buffer
, int buffersize
)
100 if ((retval
= __proc_info(PROC_INFO_CALL_PIDINFO
, pid
, flavor
, arg
, buffer
, buffersize
)) == -1)
108 proc_pidoriginatorinfo(int flavor
, void *buffer
, int buffersize
)
112 if ((retval
= __proc_info(PROC_INFO_CALL_PIDORIGINATORINFO
, getpid(), flavor
, 0, buffer
, buffersize
)) == -1)
119 proc_listcoalitions(int flavor
, int coaltype
, void *buffer
, int buffersize
)
123 if ((retval
= __proc_info(PROC_INFO_CALL_LISTCOALITIONS
, flavor
, coaltype
, 0, buffer
, buffersize
)) == -1)
130 proc_pid_rusage(int pid
, int flavor
, rusage_info_t
*buffer
)
132 return (__proc_info(PROC_INFO_CALL_PIDRUSAGE
, pid
, flavor
, 0, buffer
, 0));
136 proc_setthread_cpupercent(uint8_t percentage
, uint32_t ms_refill
)
140 /* Pack percentage and refill into a 32-bit number to match existing kernel implementation */
141 if ((percentage
>= 100) || (ms_refill
& ~0xffffffU
)) {
146 arg
= ((ms_refill
<< 8) | percentage
);
148 return (proc_rlimit_control(-1, RLIMIT_THREAD_CPULIMITS
, (void *)(uintptr_t)arg
));
152 proc_pidfdinfo(int pid
, int fd
, int flavor
, void * buffer
, int buffersize
)
156 if ((retval
= __proc_info(PROC_INFO_CALL_PIDFDINFO
, pid
, flavor
, (uint64_t)fd
, buffer
, buffersize
)) == -1)
164 proc_pidfileportinfo(int pid
, uint32_t fileport
, int flavor
, void *buffer
, int buffersize
)
168 if ((retval
= __proc_info(PROC_INFO_CALL_PIDFILEPORTINFO
, pid
, flavor
, (uint64_t)fileport
, buffer
, buffersize
)) == -1)
175 proc_name(int pid
, void * buffer
, uint32_t buffersize
)
178 struct proc_bsdinfo pbsd
;
181 if (buffersize
< sizeof(pbsd
.pbi_name
)) {
186 retval
= proc_pidinfo(pid
, PROC_PIDTBSDINFO
, (uint64_t)0, &pbsd
, sizeof(struct proc_bsdinfo
));
188 if (pbsd
.pbi_name
[0]) {
189 bcopy(&pbsd
.pbi_name
, buffer
, sizeof(pbsd
.pbi_name
));
191 bcopy(&pbsd
.pbi_comm
, buffer
, sizeof(pbsd
.pbi_comm
));
193 len
= (int)strlen(buffer
);
200 proc_regionfilename(int pid
, uint64_t address
, void * buffer
, uint32_t buffersize
)
203 struct proc_regionwithpathinfo reginfo
;
205 if (buffersize
< MAXPATHLEN
) {
210 retval
= proc_pidinfo(pid
, PROC_PIDREGIONPATHINFO
, (uint64_t)address
, ®info
, sizeof(struct proc_regionwithpathinfo
));
212 len
= (int)strlen(®info
.prp_vip
.vip_path
[0]);
214 if (len
> MAXPATHLEN
)
216 bcopy(®info
.prp_vip
.vip_path
[0], buffer
, len
);
226 proc_kmsgbuf(void * buffer
, uint32_t buffersize
)
230 if ((retval
= __proc_info(PROC_INFO_CALL_KERNMSGBUF
, 0, 0, (uint64_t)0, buffer
, buffersize
)) == -1)
236 proc_pidpath(int pid
, void * buffer
, uint32_t buffersize
)
240 if (buffersize
< PROC_PIDPATHINFO_SIZE
) {
244 if (buffersize
> PROC_PIDPATHINFO_MAXSIZE
) {
249 retval
= __proc_info(PROC_INFO_CALL_PIDINFO
, pid
, PROC_PIDPATHINFO
, (uint64_t)0, buffer
, buffersize
);
251 len
= (int)strlen(buffer
);
259 proc_libversion(int *major
, int * minor
)
270 proc_setpcontrol(const int control
)
274 if (control
< PROC_SETPC_NONE
|| control
> PROC_SETPC_TERMINATE
)
277 if ((retval
= __proc_info(PROC_INFO_CALL_SETCONTROL
, getpid(), PROC_SELFSET_PCONTROL
, (uint64_t)control
, NULL
, 0)) == -1)
284 __private_extern__
int
285 proc_setthreadname(void * buffer
, int buffersize
)
289 retval
= __proc_info(PROC_INFO_CALL_SETCONTROL
, getpid(), PROC_SELFSET_THREADNAME
, (uint64_t)0, buffer
, buffersize
);
298 proc_track_dirty(pid_t pid
, uint32_t flags
)
300 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL
, pid
, PROC_DIRTYCONTROL_TRACK
, flags
, NULL
, 0) == -1) {
308 proc_set_dirty(pid_t pid
, bool dirty
)
310 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL
, pid
, PROC_DIRTYCONTROL_SET
, dirty
, NULL
, 0) == -1) {
318 proc_get_dirty(pid_t pid
, uint32_t *flags
)
326 retval
= __proc_info(PROC_INFO_CALL_DIRTYCONTROL
, pid
, PROC_DIRTYCONTROL_GET
, 0, NULL
, 0);
337 proc_clear_dirty(pid_t pid
, uint32_t flags
)
339 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL
, pid
, PROC_DIRTYCONTROL_CLEAR
, flags
, NULL
, 0) == -1) {
347 proc_terminate(pid_t pid
, int *sig
)
355 retval
= __proc_info(PROC_INFO_CALL_TERMINATE
, pid
, 0, 0, NULL
, 0);
366 proc_set_cpumon_params(pid_t pid
, int percentage
, int interval
)
368 proc_policy_cpuusage_attr_t attr
;
370 attr
.ppattr_cpu_attr
= PROC_POLICY_RSRCACT_NOTIFY_EXC
;
371 attr
.ppattr_cpu_percentage
= percentage
;
372 attr
.ppattr_cpu_attr_interval
= (uint64_t)interval
;
373 attr
.ppattr_cpu_attr_deadline
= 0;
375 return(__process_policy(PROC_POLICY_SCOPE_PROCESS
, PROC_POLICY_ACTION_SET
, PROC_POLICY_RESOURCE_USAGE
,
376 PROC_POLICY_RUSAGE_CPU
, (proc_policy_attribute_t
*)&attr
, pid
, 0));
380 proc_get_cpumon_params(pid_t pid
, int *percentage
, int *interval
)
382 proc_policy_cpuusage_attr_t attr
;
385 ret
= __process_policy(PROC_POLICY_SCOPE_PROCESS
, PROC_POLICY_ACTION_GET
, PROC_POLICY_RESOURCE_USAGE
,
386 PROC_POLICY_RUSAGE_CPU
, (proc_policy_attribute_t
*)&attr
, pid
, 0);
388 if ((ret
== 0) && (attr
.ppattr_cpu_attr
== PROC_POLICY_RSRCACT_NOTIFY_EXC
)) {
389 *percentage
= attr
.ppattr_cpu_percentage
;
390 *interval
= (int)attr
.ppattr_cpu_attr_interval
;
400 proc_set_cpumon_defaults(pid_t pid
)
402 proc_policy_cpuusage_attr_t attr
;
404 attr
.ppattr_cpu_attr
= PROC_POLICY_RSRCACT_NOTIFY_EXC
;
405 attr
.ppattr_cpu_percentage
= PROC_POLICY_CPUMON_DEFAULTS
;
406 attr
.ppattr_cpu_attr_interval
= 0;
407 attr
.ppattr_cpu_attr_deadline
= 0;
409 return(__process_policy(PROC_POLICY_SCOPE_PROCESS
, PROC_POLICY_ACTION_SET
, PROC_POLICY_RESOURCE_USAGE
,
410 PROC_POLICY_RUSAGE_CPU
, (proc_policy_attribute_t
*)&attr
, pid
, 0));
414 proc_disable_cpumon(pid_t pid
)
416 proc_policy_cpuusage_attr_t attr
;
418 attr
.ppattr_cpu_attr
= PROC_POLICY_RSRCACT_NOTIFY_EXC
;
419 attr
.ppattr_cpu_percentage
= PROC_POLICY_CPUMON_DISABLE
;
420 attr
.ppattr_cpu_attr_interval
= 0;
421 attr
.ppattr_cpu_attr_deadline
= 0;
423 return(__process_policy(PROC_POLICY_SCOPE_PROCESS
, PROC_POLICY_ACTION_SET
, PROC_POLICY_RESOURCE_USAGE
,
424 PROC_POLICY_RUSAGE_CPU
, (proc_policy_attribute_t
*)&attr
, pid
, 0));
429 * Turn on the CPU usage monitor using the supplied parameters, and make
430 * violations of the monitor fatal.
432 * Returns: 0 on success;
433 * -1 on failure and sets errno
436 proc_set_cpumon_params_fatal(pid_t pid
, int percentage
, int interval
)
438 int current_percentage
= 0;
439 int current_interval
= 0; /* intervals are in seconds */
442 if ((percentage
<= 0) || (interval
<= 0)) {
448 * Do a simple query to see if CPU monitoring is
449 * already active. If either the percentage or the
450 * interval is nonzero, then CPU monitoring is
451 * already in use for this process.
453 (void)proc_get_cpumon_params(pid
, ¤t_percentage
, ¤t_interval
);
454 if (current_percentage
|| current_interval
)
457 * The CPU monitor appears to be active.
458 * We choose not to disturb those settings.
464 if ((ret
= proc_set_cpumon_params(pid
, percentage
, interval
)) != 0) {
465 /* Failed to activate the CPU monitor */
469 if ((ret
= proc_rlimit_control(pid
, RLIMIT_CPU_USAGE_MONITOR
, CPUMON_MAKE_FATAL
)) != 0) {
470 /* Failed to set termination, back out the CPU monitor settings. */
471 (void)proc_disable_cpumon(pid
);
478 proc_set_wakemon_params(pid_t pid
, int rate_hz
, int flags __unused
)
480 struct proc_rlimit_control_wakeupmon params
;
482 params
.wm_flags
= WAKEMON_ENABLE
;
483 params
.wm_rate
= rate_hz
;
485 return (proc_rlimit_control(pid
, RLIMIT_WAKEUPS_MONITOR
, ¶ms
));
488 #ifndef WAKEMON_GET_PARAMS
489 #define WAKEMON_GET_PARAMS 0x4
490 #define WAKEMON_SET_DEFAULTS 0x8
494 proc_get_wakemon_params(pid_t pid
, int *rate_hz
, int *flags
)
496 struct proc_rlimit_control_wakeupmon params
;
499 params
.wm_flags
= WAKEMON_GET_PARAMS
;
501 if ((error
= proc_rlimit_control(pid
, RLIMIT_WAKEUPS_MONITOR
, ¶ms
)) != 0) {
505 *rate_hz
= params
.wm_rate
;
506 *flags
= params
.wm_flags
;
512 proc_set_wakemon_defaults(pid_t pid
)
514 struct proc_rlimit_control_wakeupmon params
;
516 params
.wm_flags
= WAKEMON_ENABLE
| WAKEMON_SET_DEFAULTS
;
519 return (proc_rlimit_control(pid
, RLIMIT_WAKEUPS_MONITOR
, ¶ms
));
523 proc_disable_wakemon(pid_t pid
)
525 struct proc_rlimit_control_wakeupmon params
;
527 params
.wm_flags
= WAKEMON_DISABLE
;
530 return (proc_rlimit_control(pid
, RLIMIT_WAKEUPS_MONITOR
, ¶ms
));
534 proc_list_uptrs(int pid
, uint64_t *buf
, uint32_t bufsz
)
539 int knote_max
= 4096; /* arbitrary starting point */
541 /* if buffer is empty, this call simply counts the knotes */
542 if (bufsz
> 0 && buf
== NULL
) {
547 struct proc_fdinfo fdlist
[OPEN_MAX
];
548 nfds
= proc_pidinfo(pid
, PROC_PIDLISTFDS
, 0, fdlist
, OPEN_MAX
*sizeof(struct proc_fdinfo
));
549 if (nfds
<= 0 || nfds
> OPEN_MAX
) {
553 struct kevent_extinfo
*kqext
= malloc(knote_max
* sizeof(struct kevent_extinfo
));
559 for (i
= 0; i
< nfds
; i
++) {
560 if (fdlist
[i
].proc_fdtype
!= PROX_FDTYPE_KQUEUE
) {
565 nkns
= __proc_info(PROC_INFO_CALL_PIDFDINFO
, pid
, PROC_PIDFDKQUEUE_EXTINFO
,
566 (uint64_t)fdlist
[i
].proc_fd
, kqext
, knote_max
* sizeof(struct kevent_extinfo
));
568 if (errno
== EBADF
) {
569 /* the FD table can change after enumerating the FDs */
576 if (nkns
> knote_max
) {
577 /* there are more knotes than we requested - try again with a
580 knote_max
= nkns
+ 32; /* small margin in case of extra knotes */
581 kqext
= malloc(knote_max
* sizeof(struct kevent_extinfo
));
589 for (j
= 0; j
< nkns
; j
++) {
590 if (kqext
[j
].kqext_kev
.udata
== 0) {
594 if (bufsz
>= sizeof(uint64_t)) {
595 *buf
++ = kqext
[j
].kqext_kev
.udata
;
596 bufsz
-= sizeof(uint64_t);
608 /* Donate importance to adaptive processes from this process */
610 proc_donate_importance_boost()
614 rval
= __process_policy(PROC_POLICY_SCOPE_PROCESS
,
615 PROC_POLICY_ACTION_SET
,
617 PROC_POLICY_IMP_DONATION
,
626 static __attribute__((noinline
)) void
627 proc_importance_bad_assertion(char *reason
) {
632 * Use the address of these variables as the token. This way, they can be
633 * printed in the debugger as useful names.
635 uint64_t important_boost_assertion_token
= 0xfafafafafafafafa;
636 uint64_t normal_boost_assertion_token
= 0xfbfbfbfbfbfbfbfb;
637 uint64_t non_boost_assertion_token
= 0xfcfcfcfcfcfcfcfc;
638 uint64_t denap_boost_assertion_token
= 0xfdfdfdfdfdfdfdfd;
641 * Accept the boost on a message, or request another boost assertion
642 * if we have already accepted the implicit boost for this message.
644 * Returns EOVERFLOW if an attempt is made to take an extra assertion when not boosted.
646 * Returns EIO if the message was not a boosting message.
647 * TODO: Return a 'non-boost' token instead.
650 proc_importance_assertion_begin_with_msg(mach_msg_header_t
*msg
,
651 __unused mach_msg_trailer_t
*trailer
,
652 uint64_t *assertion_token
)
656 if (assertion_token
== NULL
)
659 #define LEGACYBOOSTMASK (MACH_MSGH_BITS_VOUCHER_MASK | MACH_MSGH_BITS_RAISEIMP)
660 #define LEGACYBOOSTED(m) (((m)->msgh_bits & LEGACYBOOSTMASK) == MACH_MSGH_BITS_RAISEIMP)
662 /* Is this a legacy boosted message? */
663 if (LEGACYBOOSTED(msg
)) {
666 * Have we accepted the implicit boost for this message yet?
667 * If we haven't accepted it yet, no need to call into kernel.
669 if ((msg
->msgh_bits
& MACH_MSGH_BITS_IMPHOLDASRT
) == 0) {
670 msg
->msgh_bits
|= MACH_MSGH_BITS_IMPHOLDASRT
;
671 *assertion_token
= (uint64_t) &important_boost_assertion_token
;
675 /* Request an additional boost count */
676 rval
= __process_policy(PROC_POLICY_SCOPE_PROCESS
,
677 PROC_POLICY_ACTION_HOLD
,
679 PROC_POLICY_IMP_IMPORTANT
,
682 *assertion_token
= (uint64_t) &important_boost_assertion_token
;
684 } else if (errno
== EOVERFLOW
) {
685 proc_importance_bad_assertion("Attempted to take assertion while not boosted");
697 * Drop a boost assertion.
698 * Returns EOVERFLOW on boost assertion underflow.
701 proc_importance_assertion_complete(uint64_t assertion_token
)
705 if (assertion_token
== 0)
708 if (assertion_token
== (uint64_t) &important_boost_assertion_token
) {
709 rval
= __process_policy(PROC_POLICY_SCOPE_PROCESS
,
710 PROC_POLICY_ACTION_DROP
,
712 PROC_POLICY_IMP_IMPORTANT
,
716 } else if (errno
== EOVERFLOW
) {
717 proc_importance_bad_assertion("Attempted to drop too many assertions");
723 proc_importance_bad_assertion("Attempted to drop assertion with invalid token");
729 * Accept the De-Nap boost on a message, or request another boost assertion
730 * if we have already accepted the implicit boost for this message.
732 * Interface is deprecated before it really got started - just as synonym
733 * for proc_importance_assertion_begin_with_msg() now.
736 proc_denap_assertion_begin_with_msg(mach_msg_header_t
*msg
,
737 uint64_t *assertion_token
)
739 #pragma clang diagnostic push
740 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
741 return proc_importance_assertion_begin_with_msg(msg
, NULL
, assertion_token
);
742 #pragma clang diagnostic pop
747 * Drop a denap boost assertion.
749 * Interface is deprecated before it really got started - just a synonym
750 * for proc_importance_assertion_complete() now.
753 proc_denap_assertion_complete(uint64_t assertion_token
)
755 return proc_importance_assertion_complete(assertion_token
);
760 proc_clear_vmpressure(pid_t pid
)
762 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)
768 /* set the current process as one who can resume suspended processes due to low virtual memory. Need to be root */
770 proc_set_owner_vmpressure(void)
774 if ((retval
= __proc_info(PROC_INFO_CALL_SETCONTROL
, getpid(), PROC_SELFSET_VMRSRCOWNER
, (uint64_t)0, NULL
, 0)) == -1)
780 /* mark yourself to delay idle sleep on disk IO */
782 proc_set_delayidlesleep(void)
786 if ((retval
= __proc_info(PROC_INFO_CALL_SETCONTROL
, getpid(), PROC_SELFSET_DELAYIDLESLEEP
, (uint64_t)1, NULL
, 0)) == -1)
792 /* Reset yourself to delay idle sleep on disk IO, if already set */
794 proc_clear_delayidlesleep(void)
798 if ((retval
= __proc_info(PROC_INFO_CALL_SETCONTROL
, getpid(), PROC_SELFSET_DELAYIDLESLEEP
, (uint64_t)0, NULL
, 0)) == -1)
804 /* disable the launch time backgroudn policy and restore the process to default group */
806 proc_disable_apptype(pid_t pid
, int apptype
)
809 case PROC_POLICY_OSX_APPTYPE_TAL
:
810 case PROC_POLICY_OSX_APPTYPE_DASHCLIENT
:
816 if (__process_policy(PROC_POLICY_SCOPE_PROCESS
, PROC_POLICY_ACTION_DISABLE
, PROC_POLICY_APPTYPE
, apptype
, NULL
, pid
, (uint64_t)0) != -1)
823 /* re-enable the launch time background policy if it had been disabled. */
825 proc_enable_apptype(pid_t pid
, int apptype
)
828 case PROC_POLICY_OSX_APPTYPE_TAL
:
829 case PROC_POLICY_OSX_APPTYPE_DASHCLIENT
:
836 if (__process_policy(PROC_POLICY_SCOPE_PROCESS
, PROC_POLICY_ACTION_ENABLE
, PROC_POLICY_APPTYPE
, apptype
, NULL
, pid
, (uint64_t)0) != -1)
843 #if !TARGET_IPHONE_SIMULATOR
846 proc_suppress(__unused pid_t pid
, __unused
uint64_t *generation
)
851 #endif /* !TARGET_IPHONE_SIMULATOR */