[rtems commit] libtest: Fix T_interrupt_test() in SMP configs

Sebastian Huber sebh at rtems.org
Thu Aug 6 17:16:08 UTC 2020


Module:    rtems
Branch:    master
Commit:    32f1f747cc7789d105f16227cafbe96b0371ae4d
Changeset: http://git.rtems.org/rtems/commit/?id=32f1f747cc7789d105f16227cafbe96b0371ae4d

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Thu Aug  6 19:12:55 2020 +0200

libtest: Fix T_interrupt_test() in SMP configs

Update #3199.

---

 cpukit/libtest/t-test-interrupt.c  | 45 +++++++++++++++++++++++++++++++
 testsuites/libtests/ttest02/init.c | 54 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 99 insertions(+)

diff --git a/cpukit/libtest/t-test-interrupt.c b/cpukit/libtest/t-test-interrupt.c
index 7012319..530fc74 100644
--- a/cpukit/libtest/t-test-interrupt.c
+++ b/cpukit/libtest/t-test-interrupt.c
@@ -47,6 +47,10 @@
 #include <rtems/score/userextimpl.h>
 #include <rtems/score/watchdogimpl.h>
 
+#ifdef RTEMS_SMP
+#include <rtems/score/smpimpl.h>
+#endif
+
 typedef T_interrupt_test_state (*T_interrupt_test_handler)(void *);
 
 #define T_INTERRUPT_SAMPLE_COUNT 8
@@ -61,6 +65,10 @@ typedef struct {
 	T_interrupt_test_state (*interrupt)(void *);
 	void (*blocked)(void *);
 	void *arg;
+#ifdef RTEMS_SMP
+	Per_CPU_Job job;
+	Per_CPU_Job_context job_context;
+#endif
 	Watchdog_Control wdg;
 	User_extensions_Control ext;
 	T_fixture_node node;
@@ -199,11 +207,31 @@ T_interrupt_do_nothing(void *arg)
 	(void)arg;
 }
 
+#ifdef RTEMS_SMP
+static void
+T_interrupt_blocked(void *arg)
+{
+	T_interrupt_context *ctx;
+
+	ctx = arg;
+	(*ctx->blocked)(ctx->arg);
+}
+#endif
+
 static void T_interrupt_thread_switch(Thread_Control *, Thread_Control *);
 
 static T_interrupt_context T_interrupt_instance = {
 	.interrupt = T_interrupt_continue,
 	.blocked = T_interrupt_do_nothing,
+#ifdef RTEMS_SMP
+	.job = {
+		.context = &T_interrupt_instance.job_context
+	},
+	.job_context = {
+		.handler = T_interrupt_blocked,
+		.arg = &T_interrupt_instance
+	},
+#endif
 	.wdg = WATCHDOG_INITIALIZER(T_interrupt_watchdog),
 	.ext = {
 		.Callouts = {
@@ -263,7 +291,24 @@ T_interrupt_thread_switch(Thread_Control *executing, Thread_Control *heir)
 		state = _Atomic_Load_uint(&ctx->state, ATOMIC_ORDER_RELAXED);
 
 		if (state != T_INTERRUPT_TEST_INITIAL) {
+#ifdef RTEMS_SMP
+			Per_CPU_Control *cpu_self;
+
+			/*
+			 * In SMP configurations, the thread switch extension
+			 * runs in a very restricted environment.  Interrupts
+			 * are disabled and the caller owns the per-CPU lock.
+			 * In order to avoid deadlocks at SMP lock level, we
+			 * have to use an SMP job which runs later in the
+			 * context of the inter-processor interrupt.
+			 */
+			cpu_self = _Per_CPU_Get();
+			_Per_CPU_Add_job(cpu_self, &ctx->job);
+			_SMP_Send_message(_Per_CPU_Get_index(cpu_self),
+			    SMP_MESSAGE_PERFORM_JOBS);
+#else
 			(*ctx->blocked)(ctx->arg);
+#endif
 		}
 	}
 }
diff --git a/testsuites/libtests/ttest02/init.c b/testsuites/libtests/ttest02/init.c
index 0f907e1..78c874f 100644
--- a/testsuites/libtests/ttest02/init.c
+++ b/testsuites/libtests/ttest02/init.c
@@ -152,6 +152,60 @@ T_TEST_CASE(TestInterruptFatal)
 	T_unreachable();
 }
 
+static void
+suspend(void *arg)
+{
+	rtems_status_code sc;
+	rtems_id *id;
+
+	id = arg;
+	sc = rtems_task_suspend(*id);
+	T_step_rsc_success(1, sc);
+}
+
+static T_interrupt_test_state
+do_nothing(void *arg)
+{
+	(void)arg;
+	return T_INTERRUPT_TEST_ACTION;
+}
+
+static void
+resume(void *arg)
+{
+	T_interrupt_test_state state;
+
+	state = T_interrupt_test_change_state(T_INTERRUPT_TEST_ACTION,
+	    T_INTERRUPT_TEST_DONE);
+
+	if (state == T_INTERRUPT_TEST_ACTION) {
+		rtems_status_code sc;
+		rtems_id *id;
+
+		id = arg;
+		sc = rtems_task_resume(*id);
+		T_step_rsc_success(0, sc);
+	}
+}
+
+static const T_interrupt_test_config blocked_config = {
+	.action = suspend,
+	.interrupt = do_nothing,
+	.blocked = resume,
+	.max_iteration_count = 10000
+};
+
+T_TEST_CASE(TestInterruptBlocked)
+{
+	T_interrupt_test_state state;
+	rtems_id id;
+
+	T_plan(3);
+	id = rtems_task_self();
+	state = T_interrupt_test(&blocked_config, &id);
+	T_step_eq_int(2, state, T_INTERRUPT_TEST_DONE);
+}
+
 const char rtems_test_name[] = "TTEST 2";
 
 static void



More information about the vc mailing list