From: Diego Nieto Cid <[email protected]>

  * inlcude/man/mach_host.def: add task_max_prioity RPC.
  * kern/task.h: add max_priority to task struct.
  * kern/task.c: implement task_max_priority RPC and inherit
                 max_priority from parent task (or default
                 processor set).
  * kern/thread.c: initialize new threads' max_priority from
                   the task creating the thread.
---
 include/mach/mach_host.defs |  21 +++++++
 kern/task.c                 | 109 ++++++++++++++++++++++++++++++++++++
 kern/task.h                 |   1 +
 kern/thread.c               |   1 +
 4 files changed, 132 insertions(+)

diff --git a/include/mach/mach_host.defs b/include/mach/mach_host.defs
index 70a2e866..01fc3758 100644
--- a/include/mach/mach_host.defs
+++ b/include/mach/mach_host.defs
@@ -400,3 +400,24 @@ routine    host_get_uptime64(
 routine processor_set_processors(
                set_name        : processor_set_name_t;
        out     processors_list : processor_name_array_t);
+
+/*
+ *     Set the task max priority to max_priority.
+ *
+ *     If set_priority is TRUE, the task priority is
+ *     also set to follow max_priority.
+ *
+ *     Regardless the value of set_priority, if the
+ *     max_priority is lower than the current priority
+ *     then the task priority is lowered to max_priority.
+ *
+ *     If change_threads is TRUE, the resulting parameters
+ *     of the task, max_priority and priority, are propagated
+ *     to the current threads of the task.
+ */
+routine task_max_priority(
+               host            : mach_port_t;
+               task            : task_t;
+               max_priority    : int;
+               set_priority    : boolean_t;
+               change_threads  : boolean_t);
diff --git a/kern/task.c b/kern/task.c
index 061a8fa4..61a30502 100644
--- a/kern/task.c
+++ b/kern/task.c
@@ -40,6 +40,7 @@
 #include <mach_debug/mach_debug_types.h>
 #include <ipc/ipc_space.h>
 #include <ipc/ipc_types.h>
+#include <kern/assert.h>
 #include <kern/debug.h>
 #include <kern/task.h>
 #include <kern/thread.h>
@@ -171,12 +172,18 @@ task_create_kernel(
                        pset = &default_pset;
                pset_reference(pset);
                new_task->priority = parent_task->priority;
+               new_task->max_priority = parent_task->max_priority;
+               /* at this point max_priority/priority must be valid */
+               assert(new_task->priority >= new_task->max_priority);
                task_unlock(parent_task);
        }
        else {
                pset = &default_pset;
                pset_reference(pset);
                new_task->priority = BASEPRI_USER;
+               new_task->max_priority = pset->max_priority;
+               if (new_task->max_priority > new_task->priority)
+                       new_task->priority = new_task->max_priority;
        }
        pset_lock(pset);
        pset_add_task(pset, new_task);
@@ -1375,3 +1382,105 @@ register_new_task_notification(
        new_task_notification = notification;
        return KERN_SUCCESS;
 }
+
+/*
+ *     thread_override_max_priority:
+ *
+ *     Sets the max priority of the given threead.
+ *     Will adjust priority if necessary or requested.
+ *
+ *     However, it will not rise above the processor set
+ *     max priority.
+ */
+static kern_return_t
+thread_override_max_priority(
+       thread_t        thread,
+       int             max_priority,
+       boolean_t       set_priority)
+{
+       spl_t   s;
+
+       s = splsched();
+       thread_lock(thread);
+
+       thread->max_priority = max_priority;
+       if (thread->processor_set->max_priority > max_priority)
+               thread->max_priority = thread->processor_set->max_priority;
+       if ((thread->max_priority > thread->priority) || (set_priority == TRUE))
+               thread->priority = thread->max_priority;
+
+       compute_priority(thread, TRUE);
+
+       thread_unlock(thread);
+       (void) splx(s);
+
+       return KERN_SUCCESS;
+}
+
+static
+ipc_kobject_type_t extract_host_type(const ipc_port_t port)
+{
+       ipc_kobject_type_t ikot = IKOT_NONE;
+
+       if (!IP_VALID(port))
+               return IKOT_NONE;
+
+       ip_lock(port);
+       if (ip_active(port))
+               ikot = ip_kotype(port);
+       ip_unlock(port);
+
+       if (ikot != IKOT_HOST && ikot != IKOT_HOST_PRIV)
+               ikot = IKOT_NONE;
+
+       return ikot;
+}
+
+/*
+ *     task_max_priority:
+ *
+ *     Reset the max priority for a task.
+ */
+kern_return_t
+task_max_priority(
+       const ipc_port_t        host,
+       task_t                  task,
+       int                     max_priority,
+       boolean_t               set_priority,
+       boolean_t               change_threads)
+{
+       kern_return_t ret = KERN_SUCCESS;
+       ipc_kobject_type_t ikot_host = extract_host_type(host);
+
+       if ((ikot_host == IKOT_NONE) || (task == TASK_NULL) ||
+                       invalid_pri(max_priority))
+               return KERN_INVALID_ARGUMENT;
+
+       task_lock(task);
+
+       if ((max_priority < task->max_priority) &&
+                       (ikot_host != IKOT_HOST_PRIV)) {
+               task_unlock(task);
+               return KERN_NO_ACCESS;
+       }
+
+       task->max_priority = max_priority;
+       if ((max_priority > task->priority) || (set_priority == TRUE))
+               task->priority = max_priority;
+
+       if (change_threads == TRUE) {
+               thread_t        thread;
+               queue_head_t    *list;
+
+               list = &task->thread_list;
+               queue_iterate(list, thread, thread_t, thread_list) {
+                       if (thread_override_max_priority(
+                                       thread, max_priority,
+                                       set_priority) != KERN_SUCCESS)
+                               ret = KERN_FAILURE;
+               }
+       }
+
+       task_unlock(task);
+       return ret;
+}
diff --git a/kern/task.h b/kern/task.h
index 9521e953..a23c2d93 100644
--- a/kern/task.h
+++ b/kern/task.h
@@ -80,6 +80,7 @@ struct task {
        /* User-visible scheduling information */
        int             user_stop_count;        /* outstanding stops */
        int             priority;               /* for new threads */
+       int             max_priority;           /* for task iheritance and new 
thrads */
 
        /* Statistics */
        time_value64_t  total_user_time;
diff --git a/kern/thread.c b/kern/thread.c
index 5a0989ae..739b3087 100644
--- a/kern/thread.c
+++ b/kern/thread.c
@@ -503,6 +503,7 @@ kern_return_t thread_create(
         */
 
        new_thread->priority = parent_task->priority;
+       new_thread->max_priority = parent_task->max_priority;
        if (pset->max_priority > new_thread->max_priority)
                new_thread->max_priority = pset->max_priority;
        if (new_thread->max_priority > new_thread->priority)
-- 
2.53.0


Reply via email to