From: Diego Nieto Cid <[email protected]>
---
tests/test-task.c | 320 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 320 insertions(+)
diff --git a/tests/test-task.c b/tests/test-task.c
index cbc75e23..235ea40e 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,324 @@ int test_errors()
ASSERT(err == MACH_SEND_INVALID_DEST, "task DEAD");
}
+void test_priority()
+{
+/* XXX cannot include <kern/sched.h> */
+#define BASEPRI_USER 25
+#define BASEPRI_SYSTEM 6
+
+ 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.
+ *
+ * 1. 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");
+
+ printf("[%s:%d] :: (default pset) max_priority: %d\n",
+ __FILE__, __LINE__, pset_sched.max_priority);
+ ASSERT(pset_sched.max_priority == BASEPRI_SYSTEM,
+ "expecting max_priority to be BASEPRI_SYSTEM");
+ }
+ /*
+ * 2. 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");
+
+ printf("[%s:%d] :: (new pset) max_priority: %d\n",
+ __FILE__, __LINE__, 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
+ }
+ /*
+ * 3. When a new task is assigned to the defualt set, new threads
must
+ * get a max_priority of BASEPRI_SYSTEM.
+ */
+ void test_new_thread_in_defpset_max_priority()
+ {
+ err = task_create(mach_task_self(), FALSE, &new_task);
+ ASSERT_RET(err, "task_create failed");
+#if MACH_HOST
+ err = task_assign_default(new_task, TRUE);
+ ASSERT_RET(err, "task_assign_default failed");
+#endif
+ 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");
+
+ printf("[%s:%d] :: (thread) base_priority: %d\n",
+ __FILE__, __LINE__, th_sched.base_priority);
+ printf("[%s:%d] :: (thread) max_priority: %d\n",
+ __FILE__, __LINE__, th_sched.max_priority);
+ 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");
+ }
+ /*
+ * 4. A task may lower its own priority. Any thread created
+ * afterwards shall inherit the max priority of the task.
+ */
+ void test_task_max_priority_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");
+
+ printf("[%s:%d] :: (thread) base_priority: %d\n",
+ __FILE__, __LINE__, th_sched.base_priority);
+ printf("[%s:%d] :: (thread) max_priority: %d\n",
+ __FILE__, __LINE__, 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");
+ }
+
+ /*
+ * 5. A child task shall inherit the priority and max priority
+ * of the parent task.
+ * 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_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(new_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");
+
+
+ printf("[%s:%d] :: (task) base_priority: %d\n",
+ __FILE__, __LINE__, tk_basic.base_priority);
+ printf("[%s:%d] :: (thread) base_priority: %d\n",
+ __FILE__, __LINE__, th_sched.base_priority);
+ printf("[%s:%d] :: (thread) max_priority: %d\n",
+ __FILE__, __LINE__, 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");
+ }
+
+ /*
+ * 6. A non-privileged task shall not be able to raise its
max_priority
+ * nor its priority above its current max_priority.
+ * This test works on a task with 'USER' priorities.
+ */
+ void test_task_priority_non_privileged()
+ {
+ task_t child_task;
+ /* 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;
+
+ /* Initialize a task with USER priorities in new_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,
+ BASEPRI_USER, TRUE, FALSE);
+ ASSERT_RET(err, "(task) 'USER' task setup failed");
+
+ /* Prepare a new clean task to test priority permissions */
+ err = task_create(new_task, FALSE, &child_task);
+ ASSERT_RET(err, "task_create failed");
+
+ err = task_priority(child_task, priority, FALSE);
+ ASSERT(err == KERN_NO_ACCESS, "(task) raising priority shall
fail");
+ err = task_max_priority(mach_host_self(), child_task,
+ max_priority, TRUE, FALSE);
+ ASSERT(err == KERN_NO_ACCESS, "(task) raising max priority
shall fail");
+
+ err = task_terminate(child_task);
+ ASSERT_RET(err, "task_terminate failed");
+ err = task_terminate(new_task);
+ ASSERT_RET(err, "task_terminate failed");
+ }
+
+ /*
+ * 7. A privileged task shall be able to raise its max_priority
+ * above its current max_priority.
+ */
+ void test_task_priority_privileged()
+ {
+ task_t child_task;
+ /* 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;
+
+ /* Initialize a task with USER priorities in new_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,
+ BASEPRI_USER, TRUE, FALSE);
+ ASSERT_RET(err, "(task) 'USER' task setup failed");
+
+ /* Prepare a new clean task to test priority permissions */
+ err = task_create(new_task, FALSE, &child_task);
+ ASSERT_RET(err, "task_create failed");
+
+ /* Start testing privileged priority setting */
+ err = task_max_priority(host_priv(), child_task,
+ max_priority, FALSE, FALSE);
+ ASSERT_RET(err, "(task) raising the max_priority shall
succeed");
+ err = task_priority(child_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(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");
+
+ printf("[%s:%d] :: (task) base_priority: %d\n",
+ __FILE__, __LINE__, tk_basic.base_priority);
+ printf("[%s:%d] :: (thread) base_priority: %d\n",
+ __FILE__, __LINE__, th_sched.base_priority);
+ printf("[%s:%d] :: (thread) max_priority: %d\n",
+ __FILE__, __LINE__, 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(child_task);
+ ASSERT_RET(err, "task_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_new_thread_in_defpset_max_priority();
+ test_task_max_priority_inheritance();
+ test_task_priority_inheritance();
+ test_task_priority_non_privileged();
+ test_task_priority_privileged();
+#undef BASEPRI_USER
+#undef BASEPRI_SYSTEM
+}
int main(int argc, char *argv[], int envc, char *envp[])
{
@@ -167,5 +486,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