summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2014-03-28 09:29:51 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2014-03-31 10:14:35 +0200
commitf0b4fd9c2e680b7eaf4b4710f02d1d2127cab2e0 (patch)
tree9ed0955fe442b11f92fb9f5a6e4181f21e0af456
parentscore: PR2152: Use allocator mutex for objects (diff)
downloadrtems-f0b4fd9c2e680b7eaf4b4710f02d1d2127cab2e0.tar.bz2
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.
-rw-r--r--cpukit/score/src/threadrestart.c1
-rw-r--r--testsuites/sptests/Makefile.am1
-rw-r--r--testsuites/sptests/configure.ac1
-rw-r--r--testsuites/sptests/spthreadlife01/Makefile.am19
-rw-r--r--testsuites/sptests/spthreadlife01/init.c352
-rw-r--r--testsuites/sptests/spthreadlife01/spthreadlife01.doc14
-rw-r--r--testsuites/sptests/spthreadlife01/spthreadlife01.scn2
7 files changed, 389 insertions, 1 deletions
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
+ * <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.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include <rtems.h>
+#include <rtems/libcsupport.h>
+
+#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 <rtems/confdefs.h>
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 ***