From f0b4fd9c2e680b7eaf4b4710f02d1d2127cab2e0 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 28 Mar 2014 09:29:51 +0100 Subject: score: Do not reset resource count during restart This fixes an integer underflow problem in case resources are released after a thread restart. Add new test sptests/spthreadlife01. --- cpukit/score/src/threadrestart.c | 1 - testsuites/sptests/Makefile.am | 1 + testsuites/sptests/configure.ac | 1 + testsuites/sptests/spthreadlife01/Makefile.am | 19 ++ testsuites/sptests/spthreadlife01/init.c | 352 +++++++++++++++++++++ .../sptests/spthreadlife01/spthreadlife01.doc | 14 + .../sptests/spthreadlife01/spthreadlife01.scn | 2 + 7 files changed, 389 insertions(+), 1 deletion(-) create mode 100644 testsuites/sptests/spthreadlife01/Makefile.am create mode 100644 testsuites/sptests/spthreadlife01/init.c create mode 100644 testsuites/sptests/spthreadlife01/spthreadlife01.doc create mode 100644 testsuites/sptests/spthreadlife01/spthreadlife01.scn diff --git a/cpukit/score/src/threadrestart.c b/cpukit/score/src/threadrestart.c index 985329f470..4b83edefb7 100644 --- a/cpukit/score/src/threadrestart.c +++ b/cpukit/score/src/threadrestart.c @@ -212,7 +212,6 @@ static void _Thread_Start_life_change( Priority_Control priority ) { - the_thread->resource_count = 0; the_thread->is_preemptible = the_thread->Start.is_preemptible; the_thread->budget_algorithm = the_thread->Start.budget_algorithm; the_thread->budget_callout = the_thread->Start.budget_callout; diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am index 4722d4231d..d47f6f7244 100644 --- a/testsuites/sptests/Makefile.am +++ b/testsuites/sptests/Makefile.am @@ -33,6 +33,7 @@ SUBDIRS = \ spsignal_err01 spport_err01 spmsgq_err01 spmsgq_err02 spsem_err01 \ spsem_err02 sptask_err01 spevent_err03 sptask_err03 sptask_err02 \ sptask_err04 spclock_err01 +SUBDIRS += spthreadlife01 SUBDIRS += spprofiling01 SUBDIRS += spcache01 SUBDIRS += sptls03 diff --git a/testsuites/sptests/configure.ac b/testsuites/sptests/configure.ac index 6a48dd97a0..4809bdc176 100644 --- a/testsuites/sptests/configure.ac +++ b/testsuites/sptests/configure.ac @@ -36,6 +36,7 @@ AM_CONDITIONAL(HAS_CPUSET,test x"${ac_cv_header_sys_cpuset_h}" = x"yes") # Explicitly list all Makefiles here AC_CONFIG_FILES([Makefile +spthreadlife01/Makefile spprofiling01/Makefile spcache01/Makefile sptls03/Makefile diff --git a/testsuites/sptests/spthreadlife01/Makefile.am b/testsuites/sptests/spthreadlife01/Makefile.am new file mode 100644 index 0000000000..14f9a68064 --- /dev/null +++ b/testsuites/sptests/spthreadlife01/Makefile.am @@ -0,0 +1,19 @@ +rtems_tests_PROGRAMS = spthreadlife01 +spthreadlife01_SOURCES = init.c + +dist_rtems_tests_DATA = spthreadlife01.scn spthreadlife01.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 + +LINK_OBJS = $(spthreadlife01_OBJECTS) +LINK_LIBS = $(spthreadlife01_LDLIBS) + +spthreadlife01$(EXEEXT): $(spthreadlife01_OBJECTS) $(spthreadlife01_DEPENDENCIES) + @rm -f spthreadlife01$(EXEEXT) + $(make-exe) + +include $(top_srcdir)/../automake/local.am diff --git a/testsuites/sptests/spthreadlife01/init.c b/testsuites/sptests/spthreadlife01/init.c new file mode 100644 index 0000000000..b85b98c165 --- /dev/null +++ b/testsuites/sptests/spthreadlife01/init.c @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include + +#include "tmacros.h" + +#define PRIO_INIT 1 +#define PRIO_HIGH 2 +#define PRIO_MID 3 +#define PRIO_LOW 4 + +const char rtems_test_name[] = "SPTHREADLIFE 1"; + +typedef enum { + INIT, + SET_PRIO, + SET_PRIO_DONE, + DO_OBTAIN_0, + OBTAIN_DONE_0, + DO_RELEASE_0, + RELEASE_DONE_0, + DO_OBTAIN_1, + OBTAIN_DONE_1, + RESTART_0, + RESTART_1, + RESTART_2, + RESTART_3, + DO_RELEASE_1, + RELEASE_DONE_1, + DELETE_0, + DELETE_1, + DELETE_2, + DELETE_3, + INVALID +} test_state; + +typedef struct { + rtems_id main_task_id; + rtems_id worker_task_id; + rtems_id sema_id; + test_state current; + test_state next; +} test_context; + +static test_context test_instance; + +static void wake_up_main(const test_context *ctx) +{ + rtems_status_code sc; + + sc = rtems_event_transient_send(ctx->main_task_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static void wait(void) +{ + rtems_status_code sc; + + sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static void change_state( + test_context *ctx, + test_state expected, + test_state current, + test_state next +) +{ + rtems_test_assert(ctx->current == expected); + ctx->current = current; + ctx->next = next; +} + +static void change_state_and_wait( + test_context *ctx, + test_state expected, + test_state current, + test_state next +) +{ + change_state(ctx, expected, current, next); + wait(); +} + +static void set_priority(rtems_task_priority prio) +{ + rtems_status_code sc; + + sc = rtems_task_set_priority(RTEMS_SELF, prio, &prio); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static void assert_priority(rtems_task_priority expected) +{ + rtems_status_code sc; + rtems_task_priority prio; + + sc = rtems_task_set_priority(RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &prio); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + rtems_test_assert(prio == expected); +} + +static void restart_extension( + Thread_Control *executing, + Thread_Control *restarted +) +{ + test_context *ctx = &test_instance; + rtems_status_code sc; + + rtems_test_assert(executing == restarted); + rtems_test_assert(ctx->worker_task_id == rtems_task_self()); + + switch (ctx->current) { + case RESTART_0: + ctx->current = RESTART_1; + sc = rtems_task_restart(RTEMS_SELF, 0); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + break; + case RESTART_1: + ctx->current = RESTART_2; + break; + default: + rtems_test_assert(0); + break; + } +} + +static void delete_extension( + Thread_Control *executing, + Thread_Control *deleted +) +{ + test_context *ctx = &test_instance; + + rtems_test_assert(executing != deleted); + rtems_test_assert(ctx->main_task_id == rtems_task_self()); + + assert_priority(PRIO_INIT); + + rtems_test_assert(ctx->current == DELETE_2); + ctx->current = DELETE_3; +} + +static void terminate_extension(Thread_Control *executing) +{ + test_context *ctx = &test_instance; + rtems_status_code sc; + + rtems_test_assert(ctx->worker_task_id == rtems_task_self()); + + assert_priority(PRIO_INIT); + + switch (ctx->current) { + case DELETE_0: + ctx->current = DELETE_1; + sc = rtems_task_delete(RTEMS_SELF); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + break; + case DELETE_1: + ctx->current = DELETE_2; + break; + default: + rtems_test_assert(0); + break; + } +} + +static void worker_task(rtems_task_argument arg) +{ + test_context *ctx = &test_instance; + + while (true) { + test_state state = ctx->current; + rtems_status_code sc; + + switch (state) { + case SET_PRIO: + assert_priority(PRIO_LOW); + set_priority(PRIO_MID); + break; + case DO_OBTAIN_0: + case DO_OBTAIN_1: + assert_priority(PRIO_MID); + sc = rtems_semaphore_obtain( + ctx->sema_id, + RTEMS_WAIT, + RTEMS_NO_TIMEOUT + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + assert_priority(PRIO_HIGH); + break; + case DO_RELEASE_0: + case DO_RELEASE_1: + assert_priority(PRIO_HIGH); + sc = rtems_semaphore_release(ctx->sema_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + switch (state) { + case DO_RELEASE_0: + assert_priority(PRIO_MID); + break; + case DO_RELEASE_1: + assert_priority(PRIO_LOW); + break; + default: + rtems_test_assert(0); + break; + } + + break; + case RESTART_2: + assert_priority(PRIO_HIGH); + break; + default: + rtems_test_assert(0); + break; + } + + ctx->current = ctx->next; + wake_up_main(ctx); + } +} + +static void create_sema(test_context *ctx) +{ + rtems_status_code sc; + + sc = rtems_semaphore_create( + rtems_build_name('S', 'E', 'M', 'A'), + 1, + RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_PRIORITY_CEILING, + PRIO_HIGH, + &ctx->sema_id + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static void test(void) +{ + test_context *ctx = &test_instance; + rtems_status_code sc; + rtems_resource_snapshot snapshot; + + ctx->main_task_id = rtems_task_self(); + + rtems_resource_snapshot_take(&snapshot); + + create_sema(ctx); + + sc = rtems_task_create( + rtems_build_name('W', 'O', 'R', 'K'), + PRIO_LOW, + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &ctx->worker_task_id + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_start(ctx->worker_task_id, worker_task, 0); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + change_state_and_wait(ctx, INIT, SET_PRIO, SET_PRIO_DONE); + change_state_and_wait(ctx, SET_PRIO_DONE, DO_OBTAIN_0, OBTAIN_DONE_0); + + sc = rtems_semaphore_delete(ctx->sema_id); + rtems_test_assert(sc == RTEMS_RESOURCE_IN_USE); + + change_state_and_wait(ctx, OBTAIN_DONE_0, DO_RELEASE_0, RELEASE_DONE_0); + + sc = rtems_semaphore_delete(ctx->sema_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + create_sema(ctx); + + change_state_and_wait(ctx, RELEASE_DONE_0, DO_OBTAIN_1, OBTAIN_DONE_1); + + sc = rtems_semaphore_delete(ctx->sema_id); + rtems_test_assert(sc == RTEMS_RESOURCE_IN_USE); + + sc = rtems_task_restart(ctx->worker_task_id, 0); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + change_state_and_wait(ctx, OBTAIN_DONE_1, RESTART_0, RESTART_3); + change_state_and_wait(ctx, RESTART_3, DO_RELEASE_1, RELEASE_DONE_1); + + sc = rtems_semaphore_delete(ctx->sema_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + change_state(ctx, RELEASE_DONE_1, DELETE_0, INVALID); + + sc = rtems_task_delete(ctx->worker_task_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + rtems_test_assert(ctx->current == DELETE_2); + + rtems_test_assert(rtems_resource_snapshot_check(&snapshot)); + + rtems_test_assert(ctx->current == DELETE_3); +} + +static void Init(rtems_task_argument arg) +{ + TEST_BEGIN(); + + test(); + + TEST_END(); + rtems_test_exit(0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER + +#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM + +#define CONFIGURE_MAXIMUM_TASKS 2 +#define CONFIGURE_MAXIMUM_SEMAPHORES 1 + +#define CONFIGURE_INITIAL_EXTENSIONS \ + { \ + .thread_restart = restart_extension, \ + .thread_delete = delete_extension, \ + .thread_terminate = terminate_extension \ + }, \ + RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT + +#include diff --git a/testsuites/sptests/spthreadlife01/spthreadlife01.doc b/testsuites/sptests/spthreadlife01/spthreadlife01.doc new file mode 100644 index 0000000000..91c816794c --- /dev/null +++ b/testsuites/sptests/spthreadlife01/spthreadlife01.doc @@ -0,0 +1,14 @@ +This file describes the directives and concepts tested by this test set. + +test set name: spthreadlife01 + +directives: + + - rtems_task_restart() + - rtems_task_delete() + +concepts: + + - Ensure that semaphores owned by a restarted thread can be deleted. + - Ensure that the task priority is adjusted properly across task restarts. + - Ensure that the task priority is adjusted properly across task deletes. diff --git a/testsuites/sptests/spthreadlife01/spthreadlife01.scn b/testsuites/sptests/spthreadlife01/spthreadlife01.scn new file mode 100644 index 0000000000..12ed3c3bda --- /dev/null +++ b/testsuites/sptests/spthreadlife01/spthreadlife01.scn @@ -0,0 +1,2 @@ +*** BEGIN OF TEST SPTHREADLIFE 1 *** +*** END OF TEST SPTHREADLIFE 1 *** -- cgit v1.2.3