From: Diego Nieto Cid <[email protected]>
---
tests/test-task.c | 455 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 455 insertions(+)
diff --git a/tests/test-task.c b/tests/test-task.c
index cbc75e23..b81d94bf 100644
--- a/tests/test-task.c
+++ b/tests/test-task.c
@@ -27,6 +27,7 @@
#include <gnumach.user.h>
#include <mach.user.h>
+#include <mach_host.user.h>
void test_task()
@@ -160,6 +161,459 @@ int test_errors()
ASSERT(err == MACH_SEND_INVALID_DEST, "task DEAD");
}
+void test_priority()
+{
+/* XXX cannot include <kern/sched.h> for BASEPRI_* constants */
+#define BASEPRI_USER 25
+#define BASEPRI_SYSTEM 6
+
+#define DEBUG_PRINT(fmt, ...) \
+ printf("[%s:%d :: %s] " fmt, \
+ __FILE__, __LINE__, __func__, \
+ ##__VA_ARGS__)
+
+ int count;
+ kern_return_t err;
+ processor_set_t pset;
+ processor_set_name_t psetn;
+ struct processor_set_sched_info pset_sched;
+ struct task_basic_info tk_basic;
+ struct thread_sched_info th_sched;
+ task_t new_task;
+ thread_t new_thread;
+ host_t host;
+
+ /*
+ * Here are short notes on what behaviour this test
+ * is attempting to guarantee and document how things
+ * should work.
+ */
+
+ /*
+ * The default processor set max priority
+ * should be set to BASEPRI_SYSTEM.
+ */
+ void test_default_pset_max_priority()
+ {
+ err = processor_set_default(mach_host_self(), &psetn);
+ ASSERT_RET(err, "processor_set_default failed");
+
+ count = PROCESSOR_SET_SCHED_INFO_COUNT;
+ err = processor_set_info(psetn, PROCESSOR_SET_SCHED_INFO,
+ &host, (processor_set_info_t) &pset_sched,
+ &count);
+ ASSERT_RET(err, "processor_set_info failed");
+
+ DEBUG_PRINT("(default pset) max_priority: %d\n",
+ pset_sched.max_priority);
+ ASSERT(pset_sched.max_priority == BASEPRI_SYSTEM,
+ "expecting max_priority to be BASEPRI_SYSTEM");
+ }
+ /*
+ * New processor sets should also get a max_priority of
+ * BASEPRI_SYSTEM.
+ */
+ void test_new_pset_max_priority()
+ {
+#if MACH_HOST
+ err = processor_set_create(mach_host_self(), &pset, &psetn);
+ ASSERT_RET(err, "processor_set_create failed");
+
+ count = PROCESSOR_SET_SCHED_INFO_COUNT;
+ err = processor_set_info(psetn, PROCESSOR_SET_SCHED_INFO,
+ &host, (processor_info_t) &pset_sched,
+ &count);
+ ASSERT_RET(err, "processor_set_info failed");
+
+ DEBUG_PRINT("(new pset) max_priority: %d\n",
+ pset_sched.max_priority);
+ ASSERT(pset_sched.max_priority == BASEPRI_SYSTEM,
+ "expecting max_priority to be BASEPRI_SYSTEM");
+
+ err = processor_set_destroy(pset);
+ ASSERT_RET(err, "processor_set_destroy failed");
+#endif
+ }
+ /*
+ * Since boot_script_task_create sets the max_priority
+ * of the task to BASEPRI_USER, check that the current
+ * task has the corresponding priorities.
+ *
+ * The priority may be observed through task_info while the
+ * max priority is only observable through a thread inheriting
+ * it on thread create.
+ */
+ void test_default_priorities()
+ {
+ /* Create thread as a proxy of max_priority */
+ err = thread_create(mach_task_self(), &new_thread);
+ ASSERT_RET(err, "thread_create failed");
+
+ count = TASK_BASIC_INFO_COUNT;
+ err = task_info(mach_task_self(), TASK_BASIC_INFO,
+ (task_info_t) &tk_basic, &count);
+ ASSERT_RET(err, "task_info failed");
+
+ count = THREAD_SCHED_INFO_COUNT;
+ err = thread_info(new_thread, THREAD_SCHED_INFO,
+ (thread_info_t) &th_sched, &count);
+ ASSERT_RET(err, "thread_info failed");
+
+
+ DEBUG_PRINT("(task) base_priority: %d\n",
+ tk_basic.base_priority);
+ DEBUG_PRINT("(thread) base_priority: %d\n",
+ th_sched.base_priority);
+ DEBUG_PRINT("(thread) max_priority: %d\n",
+ th_sched.max_priority);
+ ASSERT(tk_basic.base_priority == BASEPRI_USER,
+ "(task) expected base priority of BASEPRI_USER");
+ ASSERT(th_sched.base_priority == BASEPRI_USER,
+ "(thread) expected base priority of BASEPRI_USER");
+ ASSERT(th_sched.max_priority == BASEPRI_USER,
+ "(thread) expected max priority of BASEPRI_USER");
+
+ err = thread_terminate(new_thread);
+ ASSERT_RET(err, "thread_terminate failed");
+ }
+ /*
+ * A task may lower its own priority. Any thread created
+ * afterwards shall inherit the max priority of the task.
+ */
+ void test_task_max_priority_thread_inheritance()
+ {
+ /* Set new max priority to something we know will "win" when
+ * compared to the procesor set max_priority and that we also
+ * know it's different from the default.
+ */
+ int new_max_priority = BASEPRI_USER + 5;
+
+ err = task_create(mach_task_self(), FALSE, &new_task);
+ ASSERT_RET(err, "task_create failed");
+
+ err = task_max_priority(mach_host_self(), new_task,
+ new_max_priority, TRUE, FALSE);
+ ASSERT_RET(err, "task_max_priority");
+
+ err = thread_create(new_task, &new_thread);
+ ASSERT_RET(err, "thread_create failed");
+
+ count = THREAD_SCHED_INFO_COUNT;
+ err = thread_info(new_thread, THREAD_SCHED_INFO,
+ (thread_info_t) &th_sched, &count);
+ ASSERT_RET(err, "thread_info failed");
+
+ DEBUG_PRINT("(thread) base_priority: %d\n",
+ th_sched.base_priority);
+ DEBUG_PRINT("(thread) max_priority: %d\n",
+ th_sched.max_priority);
+ ASSERT(th_sched.base_priority == new_max_priority,
+ "(thread) expected base priority of BASEPRI_USER");
+ ASSERT(th_sched.max_priority == new_max_priority,
+ "(thread) expected max priority of BASEPRI_USER");
+
+ err = thread_terminate(new_thread);
+ ASSERT_RET(err, "thread_terminate failed");
+ err = task_terminate(new_task);
+ ASSERT_RET(err, "task_terminate failed");
+ }
+
+ /*
+ * A child task shall inherit the priority and max priority
+ * of the parent task.
+ */
+ void test_task_priority_inheritance()
+ {
+ /* Same rationale as the previous test */
+ int max_priority = BASEPRI_USER + 5;
+ task_t child_task;
+
+ err = task_create(mach_task_self(), FALSE, &new_task);
+ ASSERT_RET(err, "task_create failed");
+
+ err = task_max_priority(mach_host_self(), new_task,
+ max_priority, TRUE, FALSE);
+ ASSERT_RET(err, "task_max_priority");
+
+ /* Create the child task to check priority inheritance */
+ err = task_create(new_task, FALSE, &child_task);
+ ASSERT_RET(err, "task_create failed");
+
+ /* Create thread as a proxy of max_priority */
+ err = thread_create(child_task, &new_thread);
+ ASSERT_RET(err, "thread_create failed");
+
+ count = TASK_BASIC_INFO_COUNT;
+ err = task_info(child_task, TASK_BASIC_INFO,
+ (task_info_t) &tk_basic, &count);
+ ASSERT_RET(err, "task_info failed");
+
+ count = THREAD_SCHED_INFO_COUNT;
+ err = thread_info(new_thread, THREAD_SCHED_INFO,
+ (thread_info_t) &th_sched, &count);
+ ASSERT_RET(err, "thread_info failed");
+
+
+ DEBUG_PRINT("(task) base_priority: %d\n",
+ tk_basic.base_priority);
+ DEBUG_PRINT("(thread) base_priority: %d\n",
+ th_sched.base_priority);
+ DEBUG_PRINT("(thread) max_priority: %d\n",
+ th_sched.max_priority);
+ ASSERT(tk_basic.base_priority == max_priority,
+ "(task) expected base priority of BASEPRI_USER + 5");
+ ASSERT(th_sched.base_priority == max_priority,
+ "(thread) expected base priority of BASEPRI_USER + 5");
+ ASSERT(th_sched.max_priority == max_priority,
+ "(thread) expected max priority of BASEPRI_USER + 5");
+
+ err = thread_terminate(new_thread);
+ ASSERT_RET(err, "thread_terminate failed");
+ err = task_terminate(child_task);
+ ASSERT_RET(err, "task_terminate failed");
+ err = task_terminate(new_task);
+ ASSERT_RET(err, "task_terminate failed");
+ }
+
+ /*
+ * A non-privileged task shall not be able to raise its
max_priority
+ * nor its priority above its current max_priority.
+ */
+ void test_task_priority_non_privileged()
+ {
+ /* Set max_priority to something below the current max */
+ int max_priority = BASEPRI_USER - 10;
+ /* Set priority to something below the current max */
+ int priority = BASEPRI_USER - 5;
+
+ /* Prepare a new clean task to test priority permissions */
+ err = task_create(mach_task_self(), FALSE, &new_task);
+ ASSERT_RET(err, "task_create failed");
+
+ err = task_priority(new_task, priority, FALSE);
+ ASSERT(err == KERN_NO_ACCESS, "(task) raising priority shall
fail");
+ err = task_max_priority(mach_host_self(), new_task,
+ max_priority, TRUE, FALSE);
+ ASSERT(err == KERN_NO_ACCESS, "(task) raising max priority
shall fail");
+
+ err = task_terminate(new_task);
+ ASSERT_RET(err, "task_terminate failed");
+ }
+
+ /*
+ * A privileged task shall be able to raise its max_priority
+ * above its current max_priority.
+ */
+ void test_task_priority_privileged()
+ {
+ /* Set max_priority to something below the current max */
+ int max_priority = BASEPRI_USER - 10;
+ /*
+ * setting priority to this value should succeed after
+ * setting max_priority
+ */
+ int priority = BASEPRI_USER - 5;
+
+ /* Prepare a new clean task to test priority permissions */
+ err = task_create(mach_task_self(), FALSE, &new_task);
+ ASSERT_RET(err, "task_create failed");
+
+ /* Start testing privileged priority setting */
+ err = task_max_priority(host_priv(), new_task,
+ max_priority, FALSE, FALSE);
+ ASSERT_RET(err, "(task) raising the max_priority shall
succeed");
+ err = task_priority(new_task, priority, FALSE);
+ ASSERT_RET(err, "(task) raising priority below max_priority
shall succeed");
+
+ /* Create thread as a proxy of max_priority */
+ err = thread_create(new_task, &new_thread);
+ ASSERT_RET(err, "thread_create failed");
+
+ count = TASK_BASIC_INFO_COUNT;
+ err = task_info(new_task, TASK_BASIC_INFO,
+ (task_info_t) &tk_basic, &count);
+ ASSERT_RET(err, "task_info failed");
+
+ count = THREAD_SCHED_INFO_COUNT;
+ err = thread_info(new_thread, THREAD_SCHED_INFO,
+ (thread_info_t) &th_sched, &count);
+ ASSERT_RET(err, "thread_info failed");
+
+ DEBUG_PRINT("(task) base_priority: %d\n",
+ tk_basic.base_priority);
+ DEBUG_PRINT("(thread) base_priority: %d\n",
+ th_sched.base_priority);
+ DEBUG_PRINT("(thread) max_priority: %d\n",
+ th_sched.max_priority);
+ ASSERT(tk_basic.base_priority == priority,
+ "(task) expected base priority of BASEPRI_USER - 5");
+ ASSERT(th_sched.base_priority == priority,
+ "(thread) expected base priority of BASEPRI_USER - 5");
+ ASSERT(th_sched.max_priority == max_priority,
+ "(thread) expected max priority of BASEPRI_USER - 10");
+
+ err = thread_terminate(new_thread);
+ ASSERT_RET(err, "thread_terminate failed");
+ err = task_terminate(new_task);
+ ASSERT_RET(err, "task_terminate failed");
+ }
+
+ /*
+ * The processor set max priority must act as a ceiling
+ * of task priorities at the time that thread_create is
+ * called.
+ */
+ void test_pset_ceiling()
+ {
+ /* Set max priority above PSET default */
+ int new_max_priority = BASEPRI_SYSTEM - 1;
+
+ err = task_create(mach_task_self(), FALSE, &new_task);
+ ASSERT_RET(err, "task_create failed");
+
+ err = task_max_priority(host_priv(), new_task,
+ new_max_priority, TRUE, FALSE);
+ ASSERT_RET(err, "task_max_priority failed");
+
+ /* Create new thread to check its priority/max_priority */
+ err = thread_create(new_task, &new_thread);
+ ASSERT_RET(err, "thread_create failed");
+
+ count = THREAD_SCHED_INFO_COUNT;
+ err = thread_info(new_thread, THREAD_SCHED_INFO,
+ (thread_info_t) &th_sched, &count);
+ ASSERT_RET(err, "thread_info failed");
+
+ DEBUG_PRINT("(thread) base_priority: %d\n",
+ th_sched.base_priority);
+ DEBUG_PRINT("(thread) max_priority: %d\n",
+ th_sched.max_priority);
+ ASSERT(th_sched.base_priority == BASEPRI_SYSTEM,
+ "(thread) expected base priority of BASEPRI_SYSTEM");
+ ASSERT(th_sched.max_priority == BASEPRI_SYSTEM,
+ "(thread) expected max priority of BASEPRI_SYSTEM");
+
+ err = thread_terminate(new_thread);
+ ASSERT_RET(err, "thread_terminate failed");
+ err = task_terminate(new_task);
+ ASSERT_RET(err, "task_terminate failed");
+ }
+
+ /*
+ * Passing TRUE to change_threads should update
+ * the max priority of the current task's threads.
+ */
+ void test_updating_threads_max_priority()
+ {
+ thread_t t1, t2;
+ struct thread_sched_info ths1, ths2;
+
+ /* new priority to test task_priority */
+ int new_priority = BASEPRI_USER + 5;
+ /* new max priority to test task_max_priority */
+ int new_max_priority = BASEPRI_USER - 5;
+
+ err = task_create(mach_task_self(), TRUE, &new_task);
+ ASSERT_RET(err, "task_create failed");
+
+
+ /* Test lowering threads priorities */
+ err = thread_create(new_task, &t1);
+ ASSERT_RET(err, "thread_create failed");
+ err = thread_create(new_task, &t2);
+ ASSERT_RET(err, "thread_create failed");
+
+ err = task_priority(new_task, new_priority, TRUE);
+ ASSERT_RET(err, "task_priority failed");
+
+ /* Check effects */
+ count = THREAD_SCHED_INFO_COUNT;
+ err = thread_info(t1, THREAD_SCHED_INFO,
+ (thread_info_t) &ths1, &count);
+ ASSERT_RET(err, "thread_info failed");
+ count = THREAD_SCHED_INFO_COUNT;
+ err = thread_info(t2, THREAD_SCHED_INFO,
+ (thread_info_t) &ths2, &count);
+ ASSERT_RET(err, "thread_info failed");
+
+ DEBUG_PRINT("(t1) base_priority %d\n", ths1.base_priority);
+ DEBUG_PRINT("(t1) max_priority %d\n", ths1.max_priority);
+ DEBUG_PRINT("(t2) base_priority %d\n", ths2.base_priority);
+ DEBUG_PRINT("(t2) max_priority %d\n", ths2.max_priority);
+ ASSERT(ths1.base_priority == new_priority,
+ "(t1) expecting priority BASEPRI_USER + 5");
+ ASSERT(ths1.max_priority == BASEPRI_USER,
+ "(t1) expecting priority BASEPRI_USER");
+ ASSERT(ths2.base_priority == new_priority,
+ "(t2) expecting priority BASEPRI_USER + 5");
+ ASSERT(ths2.max_priority == BASEPRI_USER,
+ "(t2) expecting priority BASEPRI_USER");
+
+ /* Clean up */
+ err = thread_terminate(t1);
+ ASSERT_RET(err, "thread_terminate failed");
+ err = thread_terminate(t2);
+ ASSERT_RET(err, "thread_terminate failed");
+
+ /* Test raising priorities */
+ err = thread_create(new_task, &t1);
+ ASSERT_RET(err, "thread_create failed");
+ err = thread_create(new_task, &t2);
+ ASSERT_RET(err, "thread_create failed");
+
+ err = task_max_priority(host_priv(), new_task,
+ new_max_priority, TRUE, TRUE);
+ ASSERT_RET(err, "task_max_priority failed");
+
+ /* Check effects */
+ count = THREAD_SCHED_INFO_COUNT;
+ err = thread_info(t1, THREAD_SCHED_INFO,
+ (thread_info_t) &ths1, &count);
+ ASSERT_RET(err, "thread_info failed");
+ count = THREAD_SCHED_INFO_COUNT;
+ err = thread_info(t2, THREAD_SCHED_INFO,
+ (thread_info_t) &ths2, &count);
+ ASSERT_RET(err, "thread_info failed");
+
+ DEBUG_PRINT("(t1) base_priority %d\n", ths1.base_priority);
+ DEBUG_PRINT("(t1) max_priority %d\n", ths1.max_priority);
+ DEBUG_PRINT("(t2) base_priority %d\n", ths2.base_priority);
+ DEBUG_PRINT("(t2) max_priority %d\n", ths2.max_priority);
+ ASSERT(ths1.base_priority == new_max_priority,
+ "(t1) expecting priority BASEPRI_USER - 5");
+ ASSERT(ths1.max_priority == new_max_priority,
+ "(t1) expecting priority BASEPRI_USER - 5");
+ ASSERT(ths2.base_priority == new_max_priority,
+ "(t2) expecting priority BASEPRI_USER - 5");
+ ASSERT(ths2.max_priority == new_max_priority,
+ "(t2) expecting priority BASEPRI_USER - 5");
+
+ /* Clean up and exit*/
+ err = thread_terminate(t1);
+ ASSERT_RET(err, "thread_terminate failed");
+ err = thread_terminate(t2);
+ ASSERT_RET(err, "thread_terminate failed");
+
+ err = task_terminate(new_task);
+ ASSERT_RET(err, "task_terminate failed");
+ }
+
+ /*
+ * Call the tests
+ */
+ test_default_pset_max_priority();
+ test_new_pset_max_priority();
+ test_default_priorities();
+ test_task_max_priority_thread_inheritance();
+ test_task_priority_inheritance();
+ test_task_priority_non_privileged();
+ test_task_priority_privileged();
+ test_pset_ceiling();
+ test_updating_threads_max_priority();
+#undef DEBUG_PRINT
+#undef BASEPRI_USER
+#undef BASEPRI_SYSTEM
+}
int main(int argc, char *argv[], int envc, char *envp[])
{
@@ -167,5 +621,6 @@ int main(int argc, char *argv[], int envc, char *envp[])
test_task_threads();
test_new_task();
test_errors();
+ test_priority();
return 0;
}
--
2.53.0