+ if (thread != THREAD_NULL) {
+ background = proc_get_effective_thread_policy(thread, TASK_POLICY_ALL_SOCKETS_BG);
+ } else {
+ background = proc_get_effective_task_policy(proc_task(p), TASK_POLICY_ALL_SOCKETS_BG);
+ }
+
+ if (background) {
+ /*
+ * 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 == THREAD_NULL) {
+ fdt_foreach(fp, p) {
+ if (FILEGLOB_DTYPE(fp->fp_glob) == DTYPE_SOCKET) {
+ struct socket *sockp = (struct socket *)fp->fp_glob->fg_data;
+ socket_set_traffic_mgt_flags(sockp, TRAFFIC_MGT_SO_BACKGROUND);
+ sockp->so_background_thread = NULL;
+ }
+#if NECP
+ else if (FILEGLOB_DTYPE(fp->fp_glob) == DTYPE_NETPOLICY) {
+ if (necp_set_client_as_background(p, fp, background)) {
+ update_necp = true;
+ }
+ }
+#endif /* NECP */
+ }
+ }
+ } else {
+ /* 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.
+ */
+ fdt_foreach(fp, p) {
+ struct socket *sockp;
+
+ if (FILEGLOB_DTYPE(fp->fp_glob) == DTYPE_SOCKET) {
+ sockp = (struct socket *)fp->fp_glob->fg_data;
+ /* skip if only clearing this thread's sockets */
+ if ((thread) && (sockp->so_background_thread != thread)) {
+ continue;
+ }
+ socket_clear_traffic_mgt_flags(sockp, TRAFFIC_MGT_SO_BACKGROUND);
+ sockp->so_background_thread = NULL;
+ }
+#if NECP
+ else if (FILEGLOB_DTYPE(fp->fp_glob) == DTYPE_NETPOLICY) {
+ if (necp_set_client_as_background(p, fp, background)) {
+ update_necp = true;
+ }
+ }
+#endif /* NECP */
+ }
+ }
+
+ proc_fdunlock(p);
+
+#if NECP
+ if (update_necp) {
+ necp_update_all_clients();
+ }
+#endif /* NECP */
+#else
+#pragma unused(p, thread)
+#endif
+}
+
+
+/*
+ * do_background_thread
+ *
+ * Requires: thread reference
+ *
+ * Returns: 0 Success
+ * EPERM Tried to background while in vfork
+ * XXX - todo - does this need a MACF hook?
+ */
+static int
+do_background_thread(thread_t thread, int priority)
+{
+ struct uthread *ut;
+ int enable, external;
+ int rv = 0;
+
+ ut = get_bsdthread_info(thread);
+
+ /* Backgrounding is unsupported for threads in vfork */
+ if ((ut->uu_flag & UT_VFORK) != 0) {
+ return EPERM;
+ }
+
+ /* Backgrounding is unsupported for workq threads */
+ if (thread_is_static_param(thread)) {
+ return EPERM;
+ }
+
+ /* Not allowed to combine QoS and DARWIN_BG, doing so strips the QoS */
+ if (thread_has_qos_policy(thread)) {
+ thread_remove_qos_policy(thread);
+ rv = EIDRM;
+ }
+
+ /* TODO: Fail if someone passes something besides 0 or PRIO_DARWIN_BG */
+ enable = (priority == PRIO_DARWIN_BG) ? TASK_POLICY_ENABLE : TASK_POLICY_DISABLE;
+ external = (current_thread() == thread) ? TASK_POLICY_INTERNAL : TASK_POLICY_EXTERNAL;
+
+ proc_set_thread_policy(thread, external, TASK_POLICY_DARWIN_BG, enable);
+
+ return rv;
+}
+
+
+/*