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