[rtems commit] score: Add and use _Thread_Dispatch_direct()

Sebastian Huber sebh at rtems.org
Fri Nov 18 06:59:33 UTC 2016


Module:    rtems
Branch:    master
Commit:    d78d5294cd076b48160e12c2f52a940d783b4dac
Changeset: http://git.rtems.org/rtems/commit/?id=d78d5294cd076b48160e12c2f52a940d783b4dac

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Mon Nov 14 09:11:07 2016 +0100

score: Add and use _Thread_Dispatch_direct()

This function is useful for operations which synchronously block, e.g.
self restart, self deletion, yield, sleep.  It helps to detect if these
operations are called in the wrong context.  Since the thread dispatch
necessary indicator is not used, this is more robust in some SMP
situations.

Update #2751.

---

 cpukit/posix/src/nanosleep.c                      |  2 +-
 cpukit/posix/src/sched_yield.c                    |  2 +-
 cpukit/rtems/src/taskwakeafter.c                  |  2 +-
 cpukit/sapi/src/interrtext.c                      |  3 +-
 cpukit/score/include/rtems/score/interr.h         |  3 +-
 cpukit/score/include/rtems/score/threaddispatch.h | 14 ++++++++
 cpukit/score/src/threaddispatch.c                 | 16 +++++++++
 cpukit/score/src/threadrestart.c                  |  8 +----
 testsuites/sptests/Makefile.am                    |  1 +
 testsuites/sptests/configure.ac                   |  1 +
 testsuites/sptests/spfatal29/Makefile.am          | 19 ++++++++++
 testsuites/sptests/spfatal29/spfatal29.doc        | 11 ++++++
 testsuites/sptests/spfatal29/spfatal29.scn        |  3 ++
 testsuites/sptests/spfatal29/testcase.h           | 44 +++++++++++++++++++++++
 testsuites/sptests/spinternalerror02/init.c       |  2 +-
 15 files changed, 118 insertions(+), 13 deletions(-)

diff --git a/cpukit/posix/src/nanosleep.c b/cpukit/posix/src/nanosleep.c
index 38a6b8d..0fec1e4 100644
--- a/cpukit/posix/src/nanosleep.c
+++ b/cpukit/posix/src/nanosleep.c
@@ -96,7 +96,7 @@ static inline int nanosleep_yield( struct timespec *rmtp )
   executing = _Thread_Get_executing();
   cpu_self = _Thread_Dispatch_disable();
   _Thread_Yield( executing );
-  _Thread_Dispatch_enable( cpu_self );
+  _Thread_Dispatch_direct( cpu_self );
   if ( rmtp ) {
     rmtp->tv_sec = 0;
     rmtp->tv_nsec = 0;
diff --git a/cpukit/posix/src/sched_yield.c b/cpukit/posix/src/sched_yield.c
index 7e056ce..cbbcb34 100644
--- a/cpukit/posix/src/sched_yield.c
+++ b/cpukit/posix/src/sched_yield.c
@@ -30,6 +30,6 @@ int sched_yield( void )
 
   cpu_self = _Thread_Dispatch_disable();
     _Thread_Yield( _Per_CPU_Get_executing( cpu_self ) );
-  _Thread_Dispatch_enable( cpu_self );
+  _Thread_Dispatch_direct( cpu_self );
   return 0;
 }
diff --git a/cpukit/rtems/src/taskwakeafter.c b/cpukit/rtems/src/taskwakeafter.c
index fa5f6f4..568b937 100644
--- a/cpukit/rtems/src/taskwakeafter.c
+++ b/cpukit/rtems/src/taskwakeafter.c
@@ -48,6 +48,6 @@ rtems_status_code rtems_task_wake_after(
         ticks
       );
     }
-  _Thread_Dispatch_enable( cpu_self );
+  _Thread_Dispatch_direct( cpu_self );
   return RTEMS_SUCCESSFUL;
 }
diff --git a/cpukit/sapi/src/interrtext.c b/cpukit/sapi/src/interrtext.c
index 6653022..edf09db 100644
--- a/cpukit/sapi/src/interrtext.c
+++ b/cpukit/sapi/src/interrtext.c
@@ -56,7 +56,8 @@ static const char *const internal_error_text[] = {
   "INTERNAL_ERROR_RTEMS_INIT_TASK_ENTRY_IS_NULL",
   "INTERNAL_ERROR_POSIX_INIT_THREAD_ENTRY_IS_NULL",
   "INTERNAL_ERROR_THREAD_QUEUE_DEADLOCK",
-  "INTERNAL_ERROR_THREAD_QUEUE_ENQUEUE_STICKY_FROM_BAD_STATE"
+  "INTERNAL_ERROR_THREAD_QUEUE_ENQUEUE_STICKY_FROM_BAD_STATE",
+  "INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL"
 };
 
 const char *rtems_internal_error_text( rtems_fatal_code error )
diff --git a/cpukit/score/include/rtems/score/interr.h b/cpukit/score/include/rtems/score/interr.h
index dff6101..e23db5c 100644
--- a/cpukit/score/include/rtems/score/interr.h
+++ b/cpukit/score/include/rtems/score/interr.h
@@ -165,7 +165,8 @@ typedef enum {
   INTERNAL_ERROR_RTEMS_INIT_TASK_ENTRY_IS_NULL,
   INTERNAL_ERROR_POSIX_INIT_THREAD_ENTRY_IS_NULL,
   INTERNAL_ERROR_THREAD_QUEUE_DEADLOCK,
-  INTERNAL_ERROR_THREAD_QUEUE_ENQUEUE_STICKY_FROM_BAD_STATE
+  INTERNAL_ERROR_THREAD_QUEUE_ENQUEUE_STICKY_FROM_BAD_STATE,
+  INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL
 } Internal_errors_Core_list;
 
 typedef CPU_Uint32ptr Internal_errors_t;
diff --git a/cpukit/score/include/rtems/score/threaddispatch.h b/cpukit/score/include/rtems/score/threaddispatch.h
index 801970a..f4ca096 100644
--- a/cpukit/score/include/rtems/score/threaddispatch.h
+++ b/cpukit/score/include/rtems/score/threaddispatch.h
@@ -95,6 +95,20 @@ RTEMS_INLINE_ROUTINE void _Thread_Dispatch_initialization( void )
 void _Thread_Dispatch( void );
 
 /**
+ * @brief Directly do a thread dispatch.
+ *
+ * Must be called with a thread dispatch disable level of one, otherwise the
+ * INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL will occur.  This function
+ * is useful for operations which synchronously block, e.g. self restart, self
+ * deletion, yield, sleep.
+ *
+ * @param[in] cpu_self The current processor.
+ *
+ * @see _Thread_Dispatch().
+ */
+void _Thread_Dispatch_direct( Per_CPU_Control *cpu_self );
+
+/**
  * @brief Performs a thread dispatch on the current processor.
  *
  * On entry the thread dispatch disable level must be equal to one and
diff --git a/cpukit/score/src/threaddispatch.c b/cpukit/score/src/threaddispatch.c
index 36d2910..c96299c 100644
--- a/cpukit/score/src/threaddispatch.c
+++ b/cpukit/score/src/threaddispatch.c
@@ -233,3 +233,19 @@ void _Thread_Dispatch( void )
     _ISR_Local_enable( level );
   }
 }
+
+void _Thread_Dispatch_direct( Per_CPU_Control *cpu_self )
+{
+  ISR_Level level;
+
+  if ( cpu_self->thread_dispatch_disable_level != 1 ) {
+    _Terminate(
+      INTERNAL_ERROR_CORE,
+      0,
+      INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL
+    );
+  }
+
+  _ISR_Local_disable( level );
+  _Thread_Do_dispatch( cpu_self, level );
+}
diff --git a/cpukit/score/src/threadrestart.c b/cpukit/score/src/threadrestart.c
index 182cdb6..a5ed837 100644
--- a/cpukit/score/src/threadrestart.c
+++ b/cpukit/score/src/threadrestart.c
@@ -344,14 +344,8 @@ void _Thread_Life_action_handler(
 
   if ( _Thread_Is_life_terminating( previous_life_state ) ) {
     cpu_self = _Thread_Wait_for_join( executing, cpu_self );
-
     _Thread_Make_zombie( executing );
-
-    /* FIXME: Workaround for https://devel.rtems.org/ticket/2751 */
-    cpu_self->dispatch_necessary = true;
-
-    _Assert( cpu_self->heir != executing );
-    _Thread_Dispatch_enable( cpu_self );
+    _Thread_Dispatch_direct( cpu_self );
     RTEMS_UNREACHABLE();
   }
 
diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am
index 6e01eb2..54a4de7 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 += spfatal29
 _SUBDIRS += spmutex01
 _SUBDIRS += spextensions01
 _SUBDIRS += spsysinit01
diff --git a/testsuites/sptests/configure.ac b/testsuites/sptests/configure.ac
index 2899b16..76d60e3 100644
--- a/testsuites/sptests/configure.ac
+++ b/testsuites/sptests/configure.ac
@@ -193,6 +193,7 @@ spfatal20/Makefile
 spfatal24/Makefile
 spfatal25/Makefile
 spfatal27/Makefile
+spfatal29/Makefile
 spfifo01/Makefile
 spfifo02/Makefile
 spfifo03/Makefile
diff --git a/testsuites/sptests/spfatal29/Makefile.am b/testsuites/sptests/spfatal29/Makefile.am
new file mode 100644
index 0000000..23d37a9
--- /dev/null
+++ b/testsuites/sptests/spfatal29/Makefile.am
@@ -0,0 +1,19 @@
+rtems_tests_PROGRAMS = spfatal29
+spfatal29_SOURCES = ../spfatal_support/init.c ../spfatal_support/system.h testcase.h
+
+dist_rtems_tests_DATA = spfatal29.scn spfatal29.doc
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP at .cfg
+include $(top_srcdir)/../automake/compile.am
+include $(top_srcdir)/../automake/leaf.am
+
+AM_CPPFLAGS += -I$(top_srcdir)/../support/include
+
+LINK_OBJS = $(spfatal29_OBJECTS)
+LINK_LIBS = $(spfatal29_LDLIBS)
+
+spfatal29$(EXEEXT): $(spfatal29_OBJECTS) $(spfatal29_DEPENDENCIES)
+	@rm -f spfatal29$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/sptests/spfatal29/spfatal29.doc b/testsuites/sptests/spfatal29/spfatal29.doc
new file mode 100644
index 0000000..194e1f5
--- /dev/null
+++ b/testsuites/sptests/spfatal29/spfatal29.doc
@@ -0,0 +1,11 @@
+This file describes the directives and concepts tested by this test set.
+
+test set name: spfatal29
+
+directives:
+
+  - _Thread_Dispatch_force()
+
+concepts:
+
+  - Provoke the INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL fatal error.
diff --git a/testsuites/sptests/spfatal29/spfatal29.scn b/testsuites/sptests/spfatal29/spfatal29.scn
new file mode 100644
index 0000000..c640980
--- /dev/null
+++ b/testsuites/sptests/spfatal29/spfatal29.scn
@@ -0,0 +1,3 @@
+*** BEGIN OF TEST SPFATAL 29 ***
+Fatal error (yield in interrupt context) hit
+*** END OF TEST SPFATAL 29 ***
diff --git a/testsuites/sptests/spfatal29/testcase.h b/testsuites/sptests/spfatal29/testcase.h
new file mode 100644
index 0000000..096a66a
--- /dev/null
+++ b/testsuites/sptests/spfatal29/testcase.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at 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.
+ */
+
+#define FATAL_ERROR_TEST_NAME            "29"
+#define FATAL_ERROR_DESCRIPTION          "yield in interrupt context"
+#define FATAL_ERROR_EXPECTED_SOURCE      INTERNAL_ERROR_CORE
+#define FATAL_ERROR_EXPECTED_IS_INTERNAL FALSE
+#define FATAL_ERROR_EXPECTED_ERROR       INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL
+
+#define CONFIGURE_MAXIMUM_TIMERS 1
+
+static void timer(rtems_id id, void *arg)
+{
+  rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
+}
+
+void force_error()
+{
+  rtems_status_code sc;
+  rtems_id id;
+
+  sc = rtems_timer_create(
+    rtems_build_name('T', 'I', 'M', 'E'),
+    &id
+  );
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  sc = rtems_timer_fire_after(id, 1, timer, NULL);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  sc = rtems_task_delete(RTEMS_SELF);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+}
diff --git a/testsuites/sptests/spinternalerror02/init.c b/testsuites/sptests/spinternalerror02/init.c
index 3de5ef9..af9d764 100644
--- a/testsuites/sptests/spinternalerror02/init.c
+++ b/testsuites/sptests/spinternalerror02/init.c
@@ -36,7 +36,7 @@ static void test_internal_error_text(void)
   } while ( text != text_last );
 
   rtems_test_assert(
-    error - 3 == INTERNAL_ERROR_THREAD_QUEUE_ENQUEUE_STICKY_FROM_BAD_STATE
+    error - 3 == INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL
   );
 }
 



More information about the vc mailing list