On 3/18/2015 3:20 PM, Sebastian Huber wrote: > 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. > --- > cpukit/score/include/rtems/score/thread.h | 9 ++ > cpukit/score/src/threadchangepriority.c | 35 ++-- > cpukit/score/src/threadinitialize.c | 1 + > testsuites/sptests/Makefile.am | 1 + > testsuites/sptests/configure.ac | 1 + > testsuites/sptests/spintrcritical23/Makefile.am | 22 +++ > testsuites/sptests/spintrcritical23/init.c | 177 > +++++++++++++++++++++ > .../sptests/spintrcritical23/spintrcritical23.doc | 12 ++ > .../sptests/spintrcritical23/spintrcritical23.scn | 2 + > 9 files changed, 246 insertions(+), 14 deletions(-) > create mode 100644 testsuites/sptests/spintrcritical23/Makefile.am > create mode 100644 testsuites/sptests/spintrcritical23/init.c > create mode 100644 testsuites/sptests/spintrcritical23/spintrcritical23.doc > create mode 100644 testsuites/sptests/spintrcritical23/spintrcritical23.scn > > diff --git a/cpukit/score/include/rtems/score/thread.h > b/cpukit/score/include/rtems/score/thread.h > index cea88f4..11f60f3 100644 > --- a/cpukit/score/include/rtems/score/thread.h > +++ b/cpukit/score/include/rtems/score/thread.h > @@ -582,6 +582,15 @@ struct Thread_Control_struct { > Priority_Control current_priority; > /** This field is the base priority of this thread. */ > Priority_Control real_priority; > + > + /** > + * @brief Generation of the current priority value. > + * > + * It is used in _Thread_Change_priority() to serialize the update of > + * priority related data structures. > + */ > + uint32_t priority_generation; > + > /** This field is the number of mutexes currently held by this thread. */ > uint32_t resource_count; > /** This field is the blocking information for this thread. */ > diff --git a/cpukit/score/src/threadchangepriority.c > b/cpukit/score/src/threadchangepriority.c > index d61dfb8..6ee65f5 100644 > --- a/cpukit/score/src/threadchangepriority.c > +++ b/cpukit/score/src/threadchangepriority.c > @@ -29,29 +29,36 @@ void _Thread_Change_priority( > bool prepend_it > ) > { > + ISR_Level level; > + > + _ISR_Disable( level ); > + > /* > * Do not bother recomputing all the priority related information if > * we are not REALLY changing priority. > */ > if ( the_thread->current_priority != new_priority ) { > - ISR_Level level; > - > - _ISR_Disable( level ); > + uint32_t my_generation = the_thread->priority_generation + 1; > > the_thread->current_priority = new_priority; > + the_thread->priority_generation = my_generation; > > - if ( _States_Is_ready( the_thread->current_state ) ) { > - _Scheduler_Change_priority( > - the_thread, > - new_priority, > - prepend_it > - ); > - } else { > - _Scheduler_Update_priority( the_thread, new_priority ); > - } > + _Thread_queue_Requeue( the_thread->Wait.queue, the_thread ); Can we get a comment above this call that _Thread_queue_Requeue checks that the thread is actually blocked on the specified queue so we don't need to check the thread state? > - _ISR_Enable( level ); > + _ISR_Flash( level ); > > - _Thread_queue_Requeue( the_thread->Wait.queue, the_thread ); > + if ( the_thread->priority_generation == my_generation ) { > + if ( _States_Is_ready( the_thread->current_state ) ) { > + _Scheduler_Change_priority( > + the_thread, > + new_priority, > + prepend_it > + ); > + } else { > + _Scheduler_Update_priority( the_thread, new_priority ); > + } > + } > } > + > + _ISR_Enable( level ); > } > diff --git a/cpukit/score/src/threadinitialize.c > b/cpukit/score/src/threadinitialize.c > index 934fea9..993d95f 100644 > --- a/cpukit/score/src/threadinitialize.c > +++ b/cpukit/score/src/threadinitialize.c > @@ -198,6 +198,7 @@ bool _Thread_Initialize( > the_thread->Wait.queue = NULL; > the_thread->resource_count = 0; > the_thread->real_priority = priority; > + the_thread->priority_generation = 0; > the_thread->Start.initial_priority = priority; > > _Thread_Wait_flags_set( the_thread, THREAD_WAIT_FLAGS_INITIAL ); > diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am > index 0d1e687..9025ff3 100644 > --- a/testsuites/sptests/Makefile.am > +++ b/testsuites/sptests/Makefile.am > @@ -37,6 +37,7 @@ if HAS_SMP > else > _SUBDIRS += sp29 > endif > +_SUBDIRS += spintrcritical23 > _SUBDIRS += spatomic01 > _SUBDIRS += spintrcritical22 > _SUBDIRS += spsem03 > diff --git a/testsuites/sptests/configure.ac b/testsuites/sptests/configure.ac > index eef901b..ae3c763 100644 > --- a/testsuites/sptests/configure.ac > +++ b/testsuites/sptests/configure.ac > @@ -40,6 +40,7 @@ AM_CONDITIONAL(HAS_SMP,test "$rtems_cv_RTEMS_SMP" = "yes") > > # Explicitly list all Makefiles here > AC_CONFIG_FILES([Makefile > +spintrcritical23/Makefile > spatomic01/Makefile > spglobalcon01/Makefile > spintrcritical22/Makefile > diff --git a/testsuites/sptests/spintrcritical23/Makefile.am > b/testsuites/sptests/spintrcritical23/Makefile.am > new file mode 100644 > index 0000000..6baaf7b > --- /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 0000000..01cb379 > --- /dev/null > +++ b/testsuites/sptests/spintrcritical23/init.c > @@ -0,0 +1,177 @@ > +/* > + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. > + * > + * embedded brains GmbH > + * Dornierstr. 4 > + * 82178 Puchheim > + * Germany > + * <rt...@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 next_priority; > + 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 my_priority; > + > + rtems_interrupt_lock_acquire(&ctx->lock, &lock_context); > + if ( > + ctx->priority_generation != ctx->tcb->priority_generation > + && scheduler_node_unchanged(ctx) > + ) { > + ctx->done = true; > + } > + my_priority = ctx->next_priority; > + rtems_interrupt_lock_release(&ctx->lock, &lock_context); > + > + if (ctx->done) { > + rtems_status_code sc; > + > + sc = rtems_task_set_priority( > + ctx->task_id, > + my_priority, > + &my_priority > + ); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + } > +} > + > +static bool test_body(void *arg) > +{ > + test_context *ctx = arg; > + rtems_status_code sc; > + rtems_interrupt_lock_context lock_context; > + rtems_task_priority my_priority; > + rtems_task_priority last_priority; > + > + rtems_interrupt_lock_acquire(&ctx->lock, &lock_context); > + my_priority = 1 + (ctx->next_priority + 1) % 3; > + ctx->next_priority = 1 + (my_priority + 1) % 3; > + 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, > + my_priority, > + &last_priority > + ); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + if (ctx->done) { > + rtems_task_priority next_priority; > + > + sc = rtems_task_set_priority( > + ctx->task_id, > + RTEMS_CURRENT_PRIORITY, > + &next_priority > + ); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + rtems_test_assert(next_priority == ctx->next_priority); > + rtems_test_assert(next_priority != my_priority); > + } > + > + return ctx->done; > +} > + > +static void Init(rtems_task_argument arg) > +{ > + test_context *ctx = &ctx_instance; > + rtems_status_code sc; > + > + TEST_BEGIN(); > + > + sc = rtems_task_create( > + rtems_build_name('T', 'E', 'S', 'T'), > + 1, > + RTEMS_MINIMUM_STACK_SIZE, > + RTEMS_DEFAULT_MODES, > + RTEMS_DEFAULT_ATTRIBUTES, > + &ctx->task_id > + ); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + rtems_interrupt_lock_initialize(&ctx->lock, "Test"); > + 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 0000000..89e5281 > --- /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 0000000..cea3292 > --- /dev/null > +++ b/testsuites/sptests/spintrcritical23/spintrcritical23.scn > @@ -0,0 +1,2 @@ > +*** BEGIN OF TEST SPINTRCRITICAL 23 *** > +*** END OF TEST SPINTRCRITICAL 23 *** > -- > 2.1.4 > _______________________________________________ > devel mailing list > devel@rtems.org > http://lists.rtems.org/mailman/listinfo/devel
-- Joel Sherrill, Ph.D. Director of Research & Development joel.sherr...@oarcorp.com On-Line Applications Research Ask me about RTEMS: a free RTOS Huntsville AL 35805 Support Available (256) 722-9985 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel