summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2020-08-06 19:12:55 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2020-08-06 19:15:57 +0200
commit32f1f747cc7789d105f16227cafbe96b0371ae4d (patch)
treeb66b55adf56bdceb1d29ef1ebcb4bb9e71319fb8
parentpsxhdrs/strncpy/stpncpy: Fix string turncation warning (diff)
downloadrtems-32f1f747cc7789d105f16227cafbe96b0371ae4d.tar.bz2
libtest: Fix T_interrupt_test() in SMP configs
Update #3199.
-rw-r--r--cpukit/libtest/t-test-interrupt.c45
-rw-r--r--testsuites/libtests/ttest02/init.c54
2 files changed, 99 insertions, 0 deletions
diff --git a/cpukit/libtest/t-test-interrupt.c b/cpukit/libtest/t-test-interrupt.c
index 7012319dd9..530fc74188 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 0f907e15ec..78c874faf7 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