]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kern_resource.c
xnu-1504.9.17.tar.gz
[apple/xnu.git] / bsd / kern / kern_resource.c
index 02b61872ab463d2ebf642bd66fac6081f56f90c7..13b1248870397106a3211c43b5360032b8914793 100644 (file)
 
 #include <kern/task.h>
 #include <kern/clock.h>                /* for absolutetime_to_microtime() */
-#include <netinet/in.h>                /* for TRAFFIC_MGT_SO_BACKGROUND */
+#include <netinet/in.h>                /* for TRAFFIC_MGT_SO_* */
 #include <sys/socketvar.h>     /* for struct socket */
 
 #include <vm/vm_map.h>
 
 int    donice(struct proc *curp, struct proc *chgp, int n);
 int    dosetrlimit(struct proc *p, u_int which, struct rlimit *limp);
-static void do_background_socket(struct proc *curp, thread_t thread, int priority);
+int    uthread_get_background_state(uthread_t);
+static void do_background_socket(struct proc *p, thread_t thread, int priority);
 static int do_background_thread(struct proc *curp, int priority);
 static int do_background_task(struct proc *curp, int priority);
 
@@ -231,7 +232,7 @@ getpriority(struct proc *curp, struct getpriority_args *uap, int32_t *retval)
                ut = get_bsdthread_info(thread);
 
                low = 0;
-               if ( (ut->uu_flag & UT_BACKGROUND) != 0 ) {
+               if ( (ut->uu_flag & UT_BACKGROUND_TRAFFIC_MGT) != 0 ) {
                        low = 1;
                }
                break;
@@ -389,11 +390,6 @@ setpriority(struct proc *curp, struct setpriority_args *uap, __unused int32_t *r
                error = do_background_task(p, uap->prio);
                (void) do_background_socket(p, NULL, uap->prio);
                
-               proc_lock(p);
-               p->p_iopol_disk = (uap->prio == PRIO_DARWIN_BG ? 
-                               IOPOL_THROTTLE : IOPOL_DEFAULT); 
-               proc_unlock(p);
-
                found++;
                if (refheld != 0)
                        proc_rele(p);
@@ -460,6 +456,7 @@ do_background_task(struct proc *p, int priority)
        int error = 0;
        task_category_policy_data_t info;
 
+       /* set the max scheduling priority on the task */
        if (priority & PRIO_DARWIN_BG) { 
                info.role = TASK_THROTTLE_APPLICATION;
        } else {
@@ -470,21 +467,45 @@ do_background_task(struct proc *p, int priority)
                        TASK_CATEGORY_POLICY,
                        (task_policy_t) &info,
                        TASK_CATEGORY_POLICY_COUNT);
+
+       if (error)
+               goto out;
+
+       proc_lock(p);
+
+       /* mark proc structure as backgrounded */
+       if (priority & PRIO_DARWIN_BG) {
+               p->p_lflag |= P_LBACKGROUND;
+       } else {
+               p->p_lflag &= ~P_LBACKGROUND;
+       }
+
+       /* set or reset the disk I/O priority */
+       p->p_iopol_disk = (priority == PRIO_DARWIN_BG ? 
+                       IOPOL_THROTTLE : IOPOL_DEFAULT); 
+
+       proc_unlock(p);
+
+out:
        return (error);
 }
 
 static void 
-do_background_socket(struct proc *curp, thread_t thread, int priority)
+do_background_socket(struct proc *p, thread_t thread, int priority)
 {
        struct filedesc                     *fdp;
        struct fileproc                     *fp;
        int                                 i;
 
        if (priority & PRIO_DARWIN_BG) {
-               /* enable network throttle process-wide (if no thread is specified) */
+               /*
+                * For PRIO_DARWIN_PROCESS (thread is NULL), simply mark
+                * the sockets with the background flag.  There's nothing
+                * to do here for the PRIO_DARWIN_THREAD case.
+                */
                if (thread == NULL) {
-                       proc_fdlock(curp);
-                       fdp = curp->p_fd;
+                       proc_fdlock(p);
+                       fdp = p->p_fd;
 
                        for (i = 0; i < fdp->fd_nfiles; i++) {
                                struct socket       *sockp;
@@ -495,20 +516,27 @@ do_background_socket(struct proc *curp, thread_t thread, int priority)
                                        continue;
                                }
                                sockp = (struct socket *)fp->f_fglob->fg_data;
-                               sockp->so_traffic_mgt_flags |= TRAFFIC_MGT_SO_BACKGROUND;
+                               socket_set_traffic_mgt_flags(sockp, TRAFFIC_MGT_SO_BACKGROUND);
                                sockp->so_background_thread = NULL;
                        }
-                       proc_fdunlock(curp);
+                       proc_fdunlock(p);
                }
 
        } else {
+               u_int32_t       traffic_mgt;
+               /*
+                * See comments on do_background_thread().  Deregulate network
+                * traffics only for setpriority(PRIO_DARWIN_THREAD).
+                */
+               traffic_mgt = (thread == NULL) ? 0 : TRAFFIC_MGT_SO_BG_REGULATE;
+
                /* disable networking IO throttle.
                 * NOTE - It is a known limitation of the current design that we 
                 * could potentially clear TRAFFIC_MGT_SO_BACKGROUND bit for 
                 * sockets created by other threads within this process.  
                 */
-               proc_fdlock(curp);
-               fdp = curp->p_fd;
+               proc_fdlock(p);
+               fdp = p->p_fd;
                for ( i = 0; i < fdp->fd_nfiles; i++ ) {
                        struct socket       *sockp;
 
@@ -522,10 +550,10 @@ do_background_socket(struct proc *curp, thread_t thread, int priority)
                        if ((thread) && (sockp->so_background_thread != thread)) {
                                continue;
                        }
-                       sockp->so_traffic_mgt_flags &= ~TRAFFIC_MGT_SO_BACKGROUND;
+                       socket_clear_traffic_mgt_flags(sockp, TRAFFIC_MGT_SO_BACKGROUND | traffic_mgt);
                        sockp->so_background_thread = NULL;
                }
-               proc_fdunlock(curp);
+               proc_fdunlock(p);
        }
 }
 
@@ -534,6 +562,14 @@ do_background_socket(struct proc *curp, thread_t thread, int priority)
  * do_background_thread
  * Returns:    0                       Success
  * XXX - todo - does this need a MACF hook?
+ *
+ * NOTE: To maintain binary compatibility with PRIO_DARWIN_THREAD with respect
+ *      to network traffic management, UT_BACKGROUND_TRAFFIC_MGT is set/cleared
+ *      along with UT_BACKGROUND flag, as the latter alone no longer implies
+ *      any form of traffic regulation (it simply means that the thread is
+ *      background.)  With PRIO_DARWIN_PROCESS, any form of network traffic
+ *      management must be explicitly requested via whatever means appropriate,
+ *      and only TRAFFIC_MGT_SO_BACKGROUND is set via do_background_socket().
  */
 static int
 do_background_thread(struct proc *curp __unused, int priority)
@@ -552,8 +588,13 @@ do_background_thread(struct proc *curp __unused, int priority)
                        return(0);
                }
 
-               /* clear background bit in thread and disable disk IO throttle */
-               ut->uu_flag &= ~UT_BACKGROUND;
+               /*
+                * Clear background bit in thread and disable disk IO
+                * throttle as well as network traffic management.
+                * The corresponding socket flags for sockets created by
+                * this thread will be cleared in do_background_socket().
+                */
+               ut->uu_flag &= ~(UT_BACKGROUND | UT_BACKGROUND_TRAFFIC_MGT);
                ut->uu_iopol_disk = IOPOL_NORMAL;
 
                /* reset thread priority (we did not save previous value) */
@@ -570,22 +611,48 @@ do_background_thread(struct proc *curp __unused, int priority)
                return(0);
        }
 
-       /* tag thread as background and throttle disk IO */
-       ut->uu_flag |= UT_BACKGROUND;
+       /*
+        * Tag thread as background and throttle disk IO, as well
+        * as regulate network traffics.  Future sockets created
+        * by this thread will have their corresponding socket
+        * flags set at socket create time.
+        */
+       ut->uu_flag |= (UT_BACKGROUND | UT_BACKGROUND_TRAFFIC_MGT);
        ut->uu_iopol_disk = IOPOL_THROTTLE;
 
        policy.importance = INT_MIN;
        thread_policy_set( thread, THREAD_PRECEDENCE_POLICY,
                                           (thread_policy_t)&policy,
                                           THREAD_PRECEDENCE_POLICY_COUNT );
-       
+
        /* throttle networking IO happens in socket( ) syscall.
-        * If UT_BACKGROUND is set in the current thread then
-        * TRAFFIC_MGT_SO_BACKGROUND socket option is set.
+        * If UT_{BACKGROUND,BACKGROUND_TRAFFIC_MGT} is set in the current
+        * thread then TRAFFIC_MGT_SO_{BACKGROUND,BG_REGULATE} is set.
+        * Existing sockets are taken care of by do_background_socket().
         */
        return(0);
 }
 
+/*
+ * If the thread or its proc has been put into the background
+ * with setpriority(PRIO_DARWIN_{THREAD,PROCESS}, *, PRIO_DARWIN_BG),
+ * report that status.
+ *
+ * Returns: PRIO_DARWIN_BG if background
+ *                     0 if foreground
+ */
+int
+uthread_get_background_state(uthread_t uth)
+{
+       proc_t p = uth->uu_proc;
+       if (p && (p->p_lflag & P_LBACKGROUND))
+               return PRIO_DARWIN_BG;
+       
+       if (uth->uu_flag & UT_BACKGROUND)
+               return PRIO_DARWIN_BG;
+
+       return 0;
+}
 
 /*
  * Returns:    0                       Success
@@ -1247,15 +1314,16 @@ thread_is_io_throttled(void) {
        int     policy;
        struct uthread  *ut;
 
-       policy = current_proc()->p_iopol_disk;
-
        ut = get_bsdthread_info(current_thread());
 
-       if (ut->uu_iopol_disk != IOPOL_DEFAULT)
-               policy = ut->uu_iopol_disk;
+       if(ut){
+               policy = current_proc()->p_iopol_disk;
 
-       if (policy == IOPOL_THROTTLE)
-               return TRUE;
+               if (ut->uu_iopol_disk != IOPOL_DEFAULT)
+                       policy = ut->uu_iopol_disk;
 
+               if (policy == IOPOL_THROTTLE)
+                       return TRUE;
+       }
        return FALSE;
 }