mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-05 15:15:44 +00:00
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user