[PATCH gnumach v2 5/6] tests-task: add test for task/thread priority RPCs

[email protected]
Newsgroups gmane.os.hurd.bugs
Message-ID <56b30e793bd65c3ad54623162c90996cf0163a4f.1778992827.git.dnietoc@gmail.com>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.