diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2015-03-17 16:24:44 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2015-03-20 08:49:33 +0100 |
commit | 6a941e3a9986d3cfb3e4ed0139e983b0455cc73b (patch) | |
tree | 9ad4114b0eea22a82ddc51274a1b6e550ff3f4dd /testsuites/sptests/spintrcritical23 | |
parent | e0a25fb6372ea4aa23a8221d856d8319b53636d9 (diff) |
score: Fix _Thread_Change_priority()
Atomically update the current priority of a thread and the wait queue.
Serialize the scheduler update in a separate critical section with a
generation number.
New test sptests/spintrcritical23.
Close #2310.
Diffstat (limited to 'testsuites/sptests/spintrcritical23')
-rw-r--r-- | testsuites/sptests/spintrcritical23/Makefile.am | 22 | ||||
-rw-r--r-- | testsuites/sptests/spintrcritical23/init.c | 187 | ||||
-rw-r--r-- | testsuites/sptests/spintrcritical23/spintrcritical23.doc | 12 | ||||
-rw-r--r-- | testsuites/sptests/spintrcritical23/spintrcritical23.scn | 2 |
4 files changed, 223 insertions, 0 deletions
diff --git a/testsuites/sptests/spintrcritical23/Makefile.am b/testsuites/sptests/spintrcritical23/Makefile.am new file mode 100644 index 0000000000..6baaf7b77e --- /dev/null +++ b/testsuites/sptests/spintrcritical23/Makefile.am @@ -0,0 +1,22 @@ +rtems_tests_PROGRAMS = spintrcritical23 +spintrcritical23_SOURCES = init.c +spintrcritical23_SOURCES += ../spintrcritical_support/intrcritical.h +spintrcritical23_SOURCES += ../spintrcritical_support/intrcritical.c + +dist_rtems_tests_DATA = spintrcritical23.scn spintrcritical23.doc + +include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg +include $(top_srcdir)/../automake/compile.am +include $(top_srcdir)/../automake/leaf.am + +AM_CPPFLAGS += -I$(top_srcdir)/../support/include +AM_CPPFLAGS += -I$(top_srcdir)/spintrcritical_support + +LINK_OBJS = $(spintrcritical23_OBJECTS) +LINK_LIBS = $(spintrcritical23_LDLIBS) + +spintrcritical23$(EXEEXT): $(spintrcritical23_OBJECTS) $(spintrcritical23_DEPENDENCIES) + @rm -f spintrcritical23$(EXEEXT) + $(make-exe) + +include $(top_srcdir)/../automake/local.am diff --git a/testsuites/sptests/spintrcritical23/init.c b/testsuites/sptests/spintrcritical23/init.c new file mode 100644 index 0000000000..aca1285c78 --- /dev/null +++ b/testsuites/sptests/spintrcritical23/init.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include <tmacros.h> +#include <intrcritical.h> + +#include <string.h> + +#include <rtems.h> +#include <rtems/score/schedulerpriority.h> +#include <rtems/score/threadimpl.h> + +const char rtems_test_name[] = "SPINTRCRITICAL 23"; + +typedef struct { + RTEMS_INTERRUPT_LOCK_MEMBER(lock) + rtems_id task_id; + Thread_Control *tcb; + rtems_task_priority priority_task; + rtems_task_priority priority_interrupt; + uint32_t priority_generation; + Scheduler_priority_Node scheduler_node; + bool done; +} test_context; + +static test_context ctx_instance; + +static Thread_Control *get_tcb(rtems_id id) +{ + Objects_Locations location; + Thread_Control *tcb; + + tcb = _Thread_Get(id, &location); + _Objects_Put(&tcb->Object); + + rtems_test_assert(tcb != NULL && location == OBJECTS_LOCAL); + + return tcb; +} + +static bool scheduler_node_unchanged(const test_context *ctx) +{ + return memcmp( + &ctx->scheduler_node, + ctx->tcb->Scheduler.node, + sizeof(ctx->scheduler_node) + ) == 0; +} + +static void change_priority(rtems_id timer, void *arg) +{ + /* The arg is NULL */ + test_context *ctx = &ctx_instance; + rtems_interrupt_lock_context lock_context; + rtems_task_priority priority_interrupt; + rtems_task_priority priority_task; + + rtems_interrupt_lock_acquire(&ctx->lock, &lock_context); + if ( + ctx->priority_generation != ctx->tcb->priority_generation + && scheduler_node_unchanged(ctx) + ) { + ctx->done = true; + priority_interrupt = ctx->priority_interrupt; + priority_task = ctx->priority_task; + } + rtems_interrupt_lock_release(&ctx->lock, &lock_context); + + if (ctx->done) { + rtems_status_code sc; + rtems_task_priority previous; + + sc = rtems_task_set_priority( + ctx->task_id, + priority_interrupt, + &previous + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + rtems_test_assert(previous == priority_task); + } +} + +static bool test_body(void *arg) +{ + test_context *ctx = arg; + rtems_status_code sc; + rtems_interrupt_lock_context lock_context; + rtems_task_priority priority_last; + rtems_task_priority priority_task; + rtems_task_priority priority_interrupt; + rtems_task_priority previous; + + rtems_interrupt_lock_acquire(&ctx->lock, &lock_context); + priority_last = ctx->priority_task; + priority_task = 1 + (priority_last + 1) % 3; + priority_interrupt = 1 + (priority_task + 1) % 3; + ctx->priority_task = priority_task; + ctx->priority_interrupt = priority_interrupt; + ctx->priority_generation = ctx->tcb->priority_generation; + memcpy( + &ctx->scheduler_node, + ctx->tcb->Scheduler.node, + sizeof(ctx->scheduler_node) + ); + rtems_interrupt_lock_release(&ctx->lock, &lock_context); + + sc = rtems_task_set_priority( + ctx->task_id, + priority_task, + &previous + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + rtems_test_assert(previous == priority_last); + + if (ctx->done) { + sc = rtems_task_set_priority( + ctx->task_id, + RTEMS_CURRENT_PRIORITY, + &previous + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + rtems_test_assert(previous == priority_interrupt); + } + + return ctx->done; +} + +static void Init(rtems_task_argument arg) +{ + test_context *ctx = &ctx_instance; + rtems_status_code sc; + + TEST_BEGIN(); + + rtems_interrupt_lock_initialize(&ctx->lock, "Test"); + ctx->priority_task = 1; + + sc = rtems_task_create( + rtems_build_name('T', 'E', 'S', 'T'), + ctx->priority_task, + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &ctx->task_id + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + ctx->tcb = get_tcb(ctx->task_id); + + interrupt_critical_section_test(test_body, ctx, change_priority); + rtems_test_assert(ctx->done); + + TEST_END(); + rtems_test_exit(0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_MAXIMUM_TASKS 2 +#define CONFIGURE_MAXIMUM_TIMERS 1 +#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1 + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/sptests/spintrcritical23/spintrcritical23.doc b/testsuites/sptests/spintrcritical23/spintrcritical23.doc new file mode 100644 index 0000000000..89e52815f9 --- /dev/null +++ b/testsuites/sptests/spintrcritical23/spintrcritical23.doc @@ -0,0 +1,12 @@ +This file describes the directives and concepts tested by this test set. + +test set name: spintrcritical23 + +directives: + + - _Thread_Change_priority() + +concepts: + + - Ensure that priority updates work if carried out in interrupt context while + a priority change at task level is in progress. diff --git a/testsuites/sptests/spintrcritical23/spintrcritical23.scn b/testsuites/sptests/spintrcritical23/spintrcritical23.scn new file mode 100644 index 0000000000..cea3292ded --- /dev/null +++ b/testsuites/sptests/spintrcritical23/spintrcritical23.scn @@ -0,0 +1,2 @@ +*** BEGIN OF TEST SPINTRCRITICAL 23 *** +*** END OF TEST SPINTRCRITICAL 23 *** |