X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/39236c6e673c41db228275375ab7fdb0f837b292..ecc0ceb4089d506a0b8d16686a95817b331af9cb:/libsyscall/wrappers/libproc/libproc.c?ds=inline diff --git a/libsyscall/wrappers/libproc/libproc.c b/libsyscall/wrappers/libproc/libproc.c index fa0b8c16e..730a15e41 100644 --- a/libsyscall/wrappers/libproc/libproc.c +++ b/libsyscall/wrappers/libproc/libproc.c @@ -26,11 +26,12 @@ #include #include #include +#include #include #include #include -#define BUILD_LIBSYSCALL 1 #include +#include #include #include "libproc_internal.h" @@ -102,12 +103,51 @@ proc_pidinfo(int pid, int flavor, uint64_t arg, void *buffer, int buffersize) return(retval); } + +int +proc_pidoriginatorinfo(int flavor, void *buffer, int buffersize) +{ + int retval; + + if ((retval = __proc_info(PROC_INFO_CALL_PIDORIGINATORINFO, getpid(), flavor, 0, buffer, buffersize)) == -1) + return(0); + + return(retval); +} + +int +proc_listcoalitions(int flavor, int coaltype, void *buffer, int buffersize) +{ + int retval; + + if ((retval = __proc_info(PROC_INFO_CALL_LISTCOALITIONS, flavor, coaltype, 0, buffer, buffersize)) == -1) + return 0; + + return retval; +} + int proc_pid_rusage(int pid, int flavor, rusage_info_t *buffer) { return (__proc_info(PROC_INFO_CALL_PIDRUSAGE, pid, flavor, 0, buffer, 0)); } +int +proc_setthread_cpupercent(uint8_t percentage, uint32_t ms_refill) +{ + uint32_t arg = 0; + + /* Pack percentage and refill into a 32-bit number to match existing kernel implementation */ + if ((percentage >= 100) || (ms_refill & ~0xffffffU)) { + errno = EINVAL; + return -1; + } + + arg = ((ms_refill << 8) | percentage); + + return (proc_rlimit_control(-1, RLIMIT_THREAD_CPULIMITS, (void *)(uintptr_t)arg)); +} + int proc_pidfdinfo(int pid, int fd, int flavor, void * buffer, int buffersize) { @@ -150,7 +190,7 @@ proc_name(int pid, void * buffer, uint32_t buffersize) } else { bcopy(&pbsd.pbi_comm, buffer, sizeof(pbsd.pbi_comm)); } - len = strlen(buffer); + len = (int)strlen(buffer); return(len); } return(0); @@ -169,7 +209,7 @@ proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersiz retval = proc_pidinfo(pid, PROC_PIDREGIONPATHINFO, (uint64_t)address, ®info, sizeof(struct proc_regionwithpathinfo)); if (retval != -1) { - len = strlen(®info.prp_vip.vip_path[0]); + len = (int)strlen(®info.prp_vip.vip_path[0]); if (len != 0) { if (len > MAXPATHLEN) len = MAXPATHLEN; @@ -208,7 +248,7 @@ proc_pidpath(int pid, void * buffer, uint32_t buffersize) retval = __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDPATHINFO, (uint64_t)0, buffer, buffersize); if (retval != -1) { - len = strlen(buffer); + len = (int)strlen(buffer); return(len); } return (0); @@ -293,6 +333,16 @@ proc_get_dirty(pid_t pid, uint32_t *flags) return 0; } +int +proc_clear_dirty(pid_t pid, uint32_t flags) +{ + if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_CLEAR, flags, NULL, 0) == -1) { + return errno; + } + + return 0; +} + int proc_terminate(pid_t pid, int *sig) { @@ -337,7 +387,7 @@ proc_get_cpumon_params(pid_t pid, int *percentage, int *interval) if ((ret == 0) && (attr.ppattr_cpu_attr == PROC_POLICY_RSRCACT_NOTIFY_EXC)) { *percentage = attr.ppattr_cpu_percentage; - *interval = attr.ppattr_cpu_attr_interval; + *interval = (int)attr.ppattr_cpu_attr_interval; } else { *percentage = 0; *interval = 0; @@ -374,6 +424,56 @@ proc_disable_cpumon(pid_t pid) PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0)); } + +/* + * Turn on the CPU usage monitor using the supplied parameters, and make + * violations of the monitor fatal. + * + * Returns: 0 on success; + * -1 on failure and sets errno + */ +int +proc_set_cpumon_params_fatal(pid_t pid, int percentage, int interval) +{ + int current_percentage = 0; + int current_interval = 0; /* intervals are in seconds */ + int ret = 0; + + if ((percentage <= 0) || (interval <= 0)) { + errno = EINVAL; + return (-1); + } + + /* + * Do a simple query to see if CPU monitoring is + * already active. If either the percentage or the + * interval is nonzero, then CPU monitoring is + * already in use for this process. + */ + (void)proc_get_cpumon_params(pid, ¤t_percentage, ¤t_interval); + if (current_percentage || current_interval) + { + /* + * The CPU monitor appears to be active. + * We choose not to disturb those settings. + */ + errno = EBUSY; + return (-1); + } + + if ((ret = proc_set_cpumon_params(pid, percentage, interval)) != 0) { + /* Failed to activate the CPU monitor */ + return (ret); + } + + if ((ret = proc_rlimit_control(pid, RLIMIT_CPU_USAGE_MONITOR, CPUMON_MAKE_FATAL)) != 0) { + /* Failed to set termination, back out the CPU monitor settings. */ + (void)proc_disable_cpumon(pid); + } + + return (ret); +} + int proc_set_wakemon_params(pid_t pid, int rate_hz, int flags __unused) { @@ -430,142 +530,79 @@ proc_disable_wakemon(pid_t pid) return (proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, ¶ms)); } - -#if TARGET_OS_EMBEDDED - -int -proc_setcpu_percentage(pid_t pid, int action, int percentage) -{ - proc_policy_cpuusage_attr_t attr; - - bzero(&attr, sizeof(proc_policy_cpuusage_attr_t)); - attr.ppattr_cpu_attr = action; - attr.ppattr_cpu_percentage = percentage; - 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) - return(0); - else - return(errno); -} - -int -proc_setcpu_deadline(pid_t pid, int action, uint64_t deadline) -{ - proc_policy_cpuusage_attr_t attr; - - bzero(&attr, sizeof(proc_policy_cpuusage_attr_t)); - attr.ppattr_cpu_attr = action; - attr.ppattr_cpu_attr_deadline = deadline; - 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) - return(0); - else - return(errno); - -} - - int -proc_setcpu_percentage_withdeadline(pid_t pid, int action, int percentage, uint64_t deadline) +proc_list_uptrs(int pid, uint64_t *buf, uint32_t bufsz) { - proc_policy_cpuusage_attr_t attr; + int i, j; + int nfds, nkns; + int count = 0; + int knote_max = 4096; /* arbitrary starting point */ - bzero(&attr, sizeof(proc_policy_cpuusage_attr_t)); - attr.ppattr_cpu_attr = action; - attr.ppattr_cpu_percentage = percentage; - attr.ppattr_cpu_attr_deadline = deadline; - 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) - return(0); - else - return(errno); -} - -int -proc_clear_cpulimits(pid_t pid) -{ - 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) - return(0); - else - return(errno); - - -} - -int -proc_appstate(int pid, int * appstatep) -{ - int state; + /* if buffer is empty, this call simply counts the knotes */ + if (bufsz > 0 && buf == NULL) { + errno = EFAULT; + return -1; + } - 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) { - if (appstatep != NULL) - *appstatep = state; - return(0); - } else - return(errno); + struct proc_fdinfo fdlist[OPEN_MAX]; + nfds = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fdlist, OPEN_MAX*sizeof(struct proc_fdinfo)); + if (nfds <= 0 || nfds > OPEN_MAX) { + return -1; + } -} + struct kevent_extinfo *kqext = malloc(knote_max * sizeof(struct kevent_extinfo)); + if (!kqext) { + errno = ENOMEM; + return -1; + } + for (i = 0; i < nfds; i++) { + if (fdlist[i].proc_fdtype != PROX_FDTYPE_KQUEUE) { + continue; + } -int -proc_setappstate(int pid, int appstate) -{ - int state = appstate; + again: + nkns = __proc_info(PROC_INFO_CALL_PIDFDINFO, pid, PROC_PIDFDKQUEUE_EXTINFO, + (uint64_t)fdlist[i].proc_fd, kqext, knote_max * sizeof(struct kevent_extinfo)); + if (nkns < 0) { + if (errno == EBADF) { + /* the FD table can change after enumerating the FDs */ + errno = EAGAIN; + } + free(kqext); + return -1; + } - switch (state) { - case PROC_APPSTATE_NONE: - case PROC_APPSTATE_ACTIVE: - case PROC_APPSTATE_INACTIVE: - case PROC_APPSTATE_BACKGROUND: - case PROC_APPSTATE_NONUI: - break; - default: - return(EINVAL); - } - 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) - return(0); - else - return(errno); -} + if (nkns > knote_max) { + /* there are more knotes than we requested - try again with a + * larger buffer */ + free(kqext); + knote_max = nkns + 32; /* small margin in case of extra knotes */ + kqext = malloc(knote_max * sizeof(struct kevent_extinfo)); + if (!kqext) { + errno = ENOMEM; + return -1; + } + goto again; + } -int -proc_devstatusnotify(int devicestatus) -{ - int state = devicestatus; + for (j = 0; j < nkns; j++) { + if (kqext[j].kqext_kev.udata == 0) { + continue; + } - switch (devicestatus) { - case PROC_DEVSTATUS_SHORTTERM: - case PROC_DEVSTATUS_LONGTERM: - break; - default: - return(EINVAL); + if (bufsz >= sizeof(uint64_t)) { + *buf++ = kqext[j].kqext_kev.udata; + bufsz -= sizeof(uint64_t); + } + count++; + } } - 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) { - return(0); - } else - return(errno); - + free(kqext); + return count; } -int -proc_pidbind(int pid, uint64_t threadid, int bind) -{ - int state = bind; - pid_t passpid = pid; - - switch (bind) { - case PROC_PIDBIND_CLEAR: - passpid = getpid(); /* ignore pid on clear */ - break; - case PROC_PIDBIND_SET: - break; - default: - return(EINVAL); - } - 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) - return(0); - else - return(errno); -} -#endif /* TARGET_OS_EMBEDDED */ /* Donate importance to adaptive processes from this process */ @@ -574,19 +611,11 @@ proc_donate_importance_boost() { int rval; -#if TARGET_OS_EMBEDDED - rval = __process_policy(PROC_POLICY_SCOPE_PROCESS, - PROC_POLICY_ACTION_ENABLE, - PROC_POLICY_APPTYPE, - PROC_POLICY_IOS_DONATEIMP, - NULL, getpid(), (uint64_t)0); -#else /* TARGET_OS_EMBEDDED */ rval = __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_BOOST, PROC_POLICY_IMP_DONATION, NULL, getpid(), 0); -#endif /* TARGET_OS_EMBEDDED */ if (rval == 0) return (0); @@ -606,6 +635,7 @@ proc_importance_bad_assertion(char *reason) { uint64_t important_boost_assertion_token = 0xfafafafafafafafa; uint64_t normal_boost_assertion_token = 0xfbfbfbfbfbfbfbfb; uint64_t non_boost_assertion_token = 0xfcfcfcfcfcfcfcfc; +uint64_t denap_boost_assertion_token = 0xfdfdfdfdfdfdfdfd; /* * Accept the boost on a message, or request another boost assertion @@ -625,9 +655,12 @@ proc_importance_assertion_begin_with_msg(mach_msg_header_t *msg, if (assertion_token == NULL) return (EINVAL); - - /* Is this a boosting message? */ - if ((msg->msgh_bits & MACH_MSGH_BITS_RAISEIMP) != 0) { + +#define LEGACYBOOSTMASK (MACH_MSGH_BITS_VOUCHER_MASK | MACH_MSGH_BITS_RAISEIMP) +#define LEGACYBOOSTED(m) (((m)->msgh_bits & LEGACYBOOSTMASK) == MACH_MSGH_BITS_RAISEIMP) + + /* Is this a legacy boosted message? */ + if (LEGACYBOOSTED(msg)) { /* * Have we accepted the implicit boost for this message yet? @@ -640,21 +673,11 @@ proc_importance_assertion_begin_with_msg(mach_msg_header_t *msg, } /* Request an additional boost count */ - -#if TARGET_OS_EMBEDDED - rval = __process_policy(PROC_POLICY_SCOPE_PROCESS, - PROC_POLICY_ACTION_ENABLE, - PROC_POLICY_APPTYPE, - PROC_POLICY_IOS_HOLDIMP, - NULL, getpid(), 0); -#else /* TARGET_OS_EMBEDDED */ rval = __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_HOLD, PROC_POLICY_BOOST, PROC_POLICY_IMP_IMPORTANT, NULL, getpid(), 0); -#endif /* TARGET_OS_EMBEDDED */ - if (rval == 0) { *assertion_token = (uint64_t) &important_boost_assertion_token; return (0); @@ -683,21 +706,11 @@ proc_importance_assertion_complete(uint64_t assertion_token) return (0); if (assertion_token == (uint64_t) &important_boost_assertion_token) { - -#if TARGET_OS_EMBEDDED - rval = __process_policy(PROC_POLICY_SCOPE_PROCESS, - PROC_POLICY_ACTION_ENABLE, - PROC_POLICY_APPTYPE, - PROC_POLICY_IOS_DROPIMP, - NULL, getpid(), 0); -#else /* TARGET_OS_EMBEDDED */ rval = __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_DROP, PROC_POLICY_BOOST, PROC_POLICY_IMP_IMPORTANT, - NULL, getpid(), 0); -#endif /* TARGET_OS_EMBEDDED */ - + NULL, getpid(), 0); if (rval == 0) { return (0); } else if (errno == EOVERFLOW) { @@ -712,7 +725,36 @@ proc_importance_assertion_complete(uint64_t assertion_token) } } -#if !TARGET_OS_EMBEDDED +/* + * Accept the De-Nap boost on a message, or request another boost assertion + * if we have already accepted the implicit boost for this message. + * + * Interface is deprecated before it really got started - just as synonym + * for proc_importance_assertion_begin_with_msg() now. + */ +int +proc_denap_assertion_begin_with_msg(mach_msg_header_t *msg, + uint64_t *assertion_token) +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return proc_importance_assertion_begin_with_msg(msg, NULL, assertion_token); +#pragma clang diagnostic pop +} + + +/* + * Drop a denap boost assertion. + * + * Interface is deprecated before it really got started - just a synonym + * for proc_importance_assertion_complete() now. + */ +int +proc_denap_assertion_complete(uint64_t assertion_token) +{ + return proc_importance_assertion_complete(assertion_token); +} + int proc_clear_vmpressure(pid_t pid) @@ -808,7 +850,6 @@ proc_suppress(__unused pid_t pid, __unused uint64_t *generation) #endif /* !TARGET_IPHONE_SIMULATOR */ -#endif /* !TARGET_OS_EMBEDDED */