]> git.saurik.com Git - apple/xnu.git/blobdiff - libsyscall/wrappers/libproc/libproc.c
xnu-4570.20.62.tar.gz
[apple/xnu.git] / libsyscall / wrappers / libproc / libproc.c
index fa0b8c16eea8f8b93742c65859aa9ba87f4e537c..255664d9cb749bec036867fdfaf5822deefba793 100644 (file)
 #include <errno.h>
 #include <string.h>
 #include <strings.h>
+#include <stdlib.h>
 #include <sys/errno.h>
 #include <sys/msgbuf.h>
 #include <sys/resource.h>
-#define BUILD_LIBSYSCALL 1
 #include <sys/process_policy.h>
+#include <sys/event.h>
 #include <mach/message.h>
 
 #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)
 {
@@ -130,6 +170,17 @@ proc_pidfileportinfo(int pid, uint32_t fileport, int flavor, void *buffer, int b
        return (retval);
 }
 
+int
+proc_piddynkqueueinfo(int pid, int flavor, kqueue_id_t kq_id, void *buffer, int buffersize)
+{
+       int ret;
+
+       if ((ret = __proc_info(PROC_INFO_CALL_PIDDYNKQUEUEINFO, pid, flavor, (uint64_t)kq_id, buffer, buffersize)) == -1) {
+               return 0;
+       }
+
+       return ret;
+}
 
 int
 proc_name(int pid, void * buffer, uint32_t buffersize)
@@ -150,7 +201,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);
@@ -159,7 +210,7 @@ proc_name(int pid, void * buffer, uint32_t buffersize)
 int 
 proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersize)
 {
-       int retval = 0, len;
+       int retval;
        struct proc_regionwithpathinfo reginfo;
        
        if (buffersize < MAXPATHLEN) {
@@ -169,17 +220,9 @@ proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersiz
        
        retval = proc_pidinfo(pid, PROC_PIDREGIONPATHINFO, (uint64_t)address, &reginfo, sizeof(struct proc_regionwithpathinfo));
        if (retval != -1) {
-               len = strlen(&reginfo.prp_vip.vip_path[0]);
-               if (len != 0) {
-                       if (len > MAXPATHLEN)
-                               len = MAXPATHLEN;
-                       bcopy(&reginfo.prp_vip.vip_path[0], buffer, len);
-                       return(len);
-               }
-               return(0);
+               return ((int)(strlcpy(buffer, reginfo.prp_vip.vip_path, MAXPATHLEN)));
        }
-       return(0);
-                       
+       return(0);                      
 }
 
 int
@@ -208,7 +251,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 +336,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)
 {
@@ -312,11 +365,21 @@ proc_terminate(pid_t pid, int *sig)
        return 0;
 }
 
+/*
+ * XXX the _fatal() variant both checks for an existing monitor
+ * (with important policy effects on first party background apps)
+ * and validates inputs.
+ */
 int
 proc_set_cpumon_params(pid_t pid, int percentage, int interval)
 {
        proc_policy_cpuusage_attr_t attr;
 
+        /* no argument validation ...
+         * task_set_cpuusage() ignores 0 values and squashes negative
+         * values into uint32_t.
+         */
+
        attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
        attr.ppattr_cpu_percentage = percentage;
        attr.ppattr_cpu_attr_interval = (uint64_t)interval;
@@ -337,7 +400,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;
@@ -360,6 +423,16 @@ proc_set_cpumon_defaults(pid_t pid)
                PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0));
 }
 
+int
+proc_resume_cpumon(pid_t pid)
+{
+       return __process_policy(PROC_POLICY_SCOPE_PROCESS,
+                               PROC_POLICY_ACTION_ENABLE,
+                               PROC_POLICY_RESOURCE_USAGE,
+                               PROC_POLICY_RUSAGE_CPU,
+                               NULL, pid, 0);
+}
+
 int
 proc_disable_cpumon(pid_t pid)
 {
@@ -374,6 +447,60 @@ 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.
+        * 
+        * XXX: need set...() and set..fatal() to behave similarly.
+        * Currently, this check prevents 1st party apps (which get a
+        * default non-fatal monitor) not to get a fatal monitor.
+        */
+       (void)proc_get_cpumon_params(pid, &current_percentage, &current_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,8 +557,20 @@ proc_disable_wakemon(pid_t pid)
        return (proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params));
 }
 
+int
+proc_list_uptrs(int pid, uint64_t *buf, uint32_t bufsz)
+{
+       return __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDLISTUPTRS, 0,
+                       buf, bufsz);
+}
+
+int
+proc_list_dynkqueueids(int pid, kqueue_id_t *buf, uint32_t bufsz)
+{
+       return __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDLISTDYNKQUEUES, 0,
+                       buf, bufsz);
+}
 
-#if TARGET_OS_EMBEDDED
 
 int 
 proc_setcpu_percentage(pid_t pid, int action, int percentage)
@@ -447,6 +586,17 @@ proc_setcpu_percentage(pid_t pid, int action, int percentage)
                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);
+}
+
+#if TARGET_OS_EMBEDDED
+
 int
 proc_setcpu_deadline(pid_t pid, int action, uint64_t deadline)
 {
@@ -462,7 +612,6 @@ proc_setcpu_deadline(pid_t pid, int action, uint64_t deadline)
 
 }
 
-
 int
 proc_setcpu_percentage_withdeadline(pid_t pid, int action, int percentage, uint64_t deadline)
 {
@@ -478,17 +627,6 @@ proc_setcpu_percentage_withdeadline(pid_t pid, int action, int percentage, uint6
                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)
 {
@@ -503,7 +641,6 @@ proc_appstate(int pid, int * appstatep)
 
 }
 
-
 int
 proc_setappstate(int pid, int appstate)
 {
@@ -565,6 +702,12 @@ proc_pidbind(int pid, uint64_t threadid, int bind)
        else
                return(errno);
 }
+
+int
+proc_can_use_foreground_hw(int pid, uint32_t *reason)
+{
+       return __proc_info(PROC_INFO_CALL_CANUSEFGHW, pid, 0,  NULL,  reason, sizeof(*reason));
+}
 #endif /* TARGET_OS_EMBEDDED */
 
 
@@ -606,6 +749,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 +769,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 +787,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 +820,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,6 +839,36 @@ proc_importance_assertion_complete(uint64_t assertion_token)
        }
 }
 
+/*
+ * 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);
+}
+
 #if !TARGET_OS_EMBEDDED
 
 int