[PATCH 2/5] rtems: Critical fix for events
Sebastian Huber
sebastian.huber at embedded-brains.de
Wed Jan 2 17:56:35 UTC 2013
Commit 4b45c1393ce4ee3e1c2762ef3145d2bd6b5b38da marked a test in
_Event_Timeout() as debug only. This test is need in non-debug
configurations too since otherwise state corruption can happen. A
revised test sptests/spintrcritical10 checks the relevant sequences.
---
cpukit/rtems/src/eventtimeout.c | 19 +-
testsuites/sptests/spintrcritical10/init.c | 307 ++++++++++++++++++--
.../sptests/spintrcritical10/spintrcritical10.scn | 5 +-
3 files changed, 301 insertions(+), 30 deletions(-)
diff --git a/cpukit/rtems/src/eventtimeout.c b/cpukit/rtems/src/eventtimeout.c
index 58dee84..31eb043 100644
--- a/cpukit/rtems/src/eventtimeout.c
+++ b/cpukit/rtems/src/eventtimeout.c
@@ -49,13 +49,18 @@ void _Event_Timeout(
* a timeout is not allowed to occur.
*/
_ISR_Disable( level );
- #if defined(RTEMS_DEBUG)
- if ( !the_thread->Wait.count ) { /* verify thread is waiting */
- _Thread_Unnest_dispatch();
- _ISR_Enable( level );
- return;
- }
- #endif
+ /*
+ * Verify that the thread is still waiting for the event condition.
+ * This test is necessary to avoid state corruption if the timeout
+ * happens after the event condition is satisfied in
+ * _Event_Surrender(). A satisfied event condition is indicated with
+ * count set to zero.
+ */
+ if ( !the_thread->Wait.count ) {
+ _Thread_Unnest_dispatch();
+ _ISR_Enable( level );
+ return;
+ }
the_thread->Wait.count = 0;
if ( _Thread_Is_executing( the_thread ) ) {
diff --git a/testsuites/sptests/spintrcritical10/init.c b/testsuites/sptests/spintrcritical10/init.c
index 66306cd..f284780 100644
--- a/testsuites/sptests/spintrcritical10/init.c
+++ b/testsuites/sptests/spintrcritical10/init.c
@@ -2,49 +2,316 @@
* COPYRIGHT (c) 1989-2012.
* On-Line Applications Research Corporation (OAR).
*
+ * Copyright (c) 2013 embedded brains GmbH.
+ *
* 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"
+ #include "config.h"
#endif
#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1
#include <tmacros.h>
#include <intrcritical.h>
-/* forward declarations to avoid warnings */
-rtems_task Init(rtems_task_argument argument);
+#define GREEN RTEMS_EVENT_0
-rtems_id Main_task;
+#define RED RTEMS_EVENT_1
-rtems_task Init(
- rtems_task_argument ignored
-)
+#define EVENTS (GREEN | RED)
+
+#define DEADBEEF 0xdeadbeef
+
+typedef struct {
+ rtems_id timer;
+ Thread_Control *thread;
+ bool hit;
+} test_context;
+
+static void any_satisfy_before_timeout(rtems_id timer, void *arg)
{
- rtems_status_code sc;
- rtems_event_set out;
- int resets;
+ rtems_status_code sc;
+ test_context *ctx = arg;
+ const Thread_Control *thread = ctx->thread;
- puts( "\n\n*** TEST INTERRUPT CRITICAL SECTION 10 ***" );
+ if (thread->Wait.count != 0) {
+ ctx->hit = _Event_Sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED;
+
+ rtems_test_assert(thread->Wait.count == EVENTS);
+ rtems_test_assert(
+ *(rtems_event_set *) thread->Wait.return_argument == DEADBEEF
+ );
+ rtems_test_assert(thread->Wait.return_code == RTEMS_SUCCESSFUL);
+
+ sc = rtems_event_send(thread->Object.id, GREEN);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ rtems_test_assert(thread->Wait.count == 0);
+ rtems_test_assert(
+ *(rtems_event_set *) thread->Wait.return_argument == GREEN
+ );
+ rtems_test_assert(thread->Wait.return_code == RTEMS_SUCCESSFUL);
+
+ sc = rtems_event_send(thread->Object.id, RED);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ rtems_test_assert(thread->Wait.count == 0);
+ rtems_test_assert(
+ *(rtems_event_set *) thread->Wait.return_argument == GREEN
+ );
+ rtems_test_assert(thread->Wait.return_code == RTEMS_SUCCESSFUL);
+
+ _Event_Timeout(thread->Object.id, &_Event_Sync_state);
+
+ rtems_test_assert(thread->Wait.count == 0);
+ rtems_test_assert(
+ *(rtems_event_set *) thread->Wait.return_argument == GREEN
+ );
+ rtems_test_assert(thread->Wait.return_code == RTEMS_SUCCESSFUL);
+
+ if (ctx->hit) {
+ rtems_test_assert(
+ _Event_Sync_state == THREAD_BLOCKING_OPERATION_SATISFIED
+ );
+ }
+ }
+
+ sc = rtems_timer_reset(timer);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void test_any_satisfy_before_timeout(test_context *ctx)
+{
+ rtems_status_code sc;
+ int resets = 0;
+
+ puts(
+ "Init - Trying to generate any satisfied before timeout "
+ "while blocking on event"
+ );
+
+ ctx->hit = false;
+
+ interrupt_critical_section_test_support_initialize(NULL);
+
+ sc = rtems_timer_fire_after(ctx->timer, 1, any_satisfy_before_timeout, ctx);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ while (!ctx->hit && resets < 2) {
+ rtems_event_set out;
+
+ if (interrupt_critical_section_test_support_delay())
+ resets++;
+
+ out = DEADBEEF;
+ sc = rtems_event_receive(EVENTS, RTEMS_EVENT_ANY | RTEMS_WAIT, 1, &out);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+ rtems_test_assert(out == GREEN);
+
+ out = DEADBEEF;
+ sc = rtems_event_receive(EVENTS, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, 0, &out);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+ rtems_test_assert(out == RED);
+ }
+
+ sc = rtems_timer_cancel(ctx->timer);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ rtems_test_assert(ctx->hit);
+}
+
+static void all_satisfy_before_timeout(rtems_id timer, void *arg)
+{
+ rtems_status_code sc;
+ test_context *ctx = arg;
+ const Thread_Control *thread = ctx->thread;
+
+ if (thread->Wait.count != 0) {
+ ctx->hit = _Event_Sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED;
+
+ rtems_test_assert(thread->Wait.count == EVENTS);
+ rtems_test_assert(
+ *(rtems_event_set *) thread->Wait.return_argument == DEADBEEF
+ );
+ rtems_test_assert(thread->Wait.return_code == RTEMS_SUCCESSFUL);
+
+ sc = rtems_event_send(thread->Object.id, GREEN);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ rtems_test_assert(thread->Wait.count == EVENTS);
+ rtems_test_assert(
+ *(rtems_event_set *) thread->Wait.return_argument == DEADBEEF
+ );
+ rtems_test_assert(thread->Wait.return_code == RTEMS_SUCCESSFUL);
+
+ sc = rtems_event_send(thread->Object.id, RED);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ rtems_test_assert(thread->Wait.count == 0);
+ rtems_test_assert(
+ *(rtems_event_set *) thread->Wait.return_argument == EVENTS
+ );
+ rtems_test_assert(thread->Wait.return_code == RTEMS_SUCCESSFUL);
+
+ _Event_Timeout(thread->Object.id, &_Event_Sync_state);
+
+ rtems_test_assert(thread->Wait.count == 0);
+ rtems_test_assert(
+ *(rtems_event_set *) thread->Wait.return_argument == EVENTS
+ );
+ rtems_test_assert(thread->Wait.return_code == RTEMS_SUCCESSFUL);
+
+ if (ctx->hit) {
+ rtems_test_assert(
+ _Event_Sync_state == THREAD_BLOCKING_OPERATION_SATISFIED
+ );
+ }
+ }
- puts( "Init - Test may not be able to detect case is hit reliably" );
- puts( "Init - Trying to generate timeout while blocking on event" );
+ sc = rtems_timer_reset(timer);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void test_all_satisfy_before_timeout(test_context *ctx)
+{
+ rtems_status_code sc;
+ int resets = 0;
+
+ puts(
+ "Init - Trying to generate all satisfied before timeout "
+ "while blocking on event"
+ );
+
+ ctx->hit = false;
+
+ interrupt_critical_section_test_support_initialize(NULL);
- Main_task = rtems_task_self();
+ sc = rtems_timer_fire_after(ctx->timer, 1, all_satisfy_before_timeout, ctx);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
- interrupt_critical_section_test_support_initialize( NULL );
+ while (!ctx->hit && resets < 2) {
+ rtems_event_set out;
- for (resets=0 ; resets< 2 ;) {
- if ( interrupt_critical_section_test_support_delay() )
+ if (interrupt_critical_section_test_support_delay())
resets++;
- sc = rtems_event_receive( 0x01, RTEMS_DEFAULT_OPTIONS, 1, &out );
- fatal_directive_status( sc, RTEMS_TIMEOUT, "event_receive timeout" );
+ out = DEADBEEF;
+ sc = rtems_event_receive(EVENTS, RTEMS_EVENT_ALL | RTEMS_WAIT, 1, &out);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+ rtems_test_assert(out == EVENTS);
}
+ sc = rtems_timer_cancel(ctx->timer);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ rtems_test_assert(ctx->hit);
+}
+
+static void timeout_before_satisfied(rtems_id timer, void *arg)
+{
+ rtems_status_code sc;
+ test_context *ctx = arg;
+ const Thread_Control *thread = ctx->thread;
+
+ if (thread->Wait.count != 0) {
+ ctx->hit =
+ _Event_Sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED;
+
+ rtems_test_assert(thread->Wait.count == EVENTS);
+ rtems_test_assert(
+ *(rtems_event_set *) thread->Wait.return_argument == DEADBEEF
+ );
+ rtems_test_assert(thread->Wait.return_code == RTEMS_SUCCESSFUL);
+
+ _Event_Timeout(thread->Object.id, &_Event_Sync_state);
+
+ rtems_test_assert(thread->Wait.count == 0);
+ rtems_test_assert(
+ *(rtems_event_set *) thread->Wait.return_argument == DEADBEEF
+ );
+ rtems_test_assert(thread->Wait.return_code == RTEMS_TIMEOUT);
+
+ sc = rtems_event_send(thread->Object.id, EVENTS);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ rtems_test_assert(thread->Wait.count == 0);
+ rtems_test_assert(
+ *(rtems_event_set *) thread->Wait.return_argument == DEADBEEF
+ );
+ rtems_test_assert(thread->Wait.return_code == RTEMS_TIMEOUT);
+
+ if (ctx->hit) {
+ rtems_test_assert(
+ _Event_Sync_state == THREAD_BLOCKING_OPERATION_TIMEOUT
+ );
+ }
+ }
+
+ sc = rtems_timer_reset(timer);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void test_timeout_before_all_satisfy(test_context *ctx)
+{
+ rtems_status_code sc;
+ int resets = 0;
+
+ puts(
+ "Init - Trying to generate timeout before all satisfied "
+ "while blocking on event"
+ );
+
+ ctx->hit = false;
+
+ interrupt_critical_section_test_support_initialize(NULL);
+
+ sc = rtems_timer_fire_after(ctx->timer, 1, timeout_before_satisfied, ctx);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ while (!ctx->hit && resets < 2) {
+ rtems_event_set out;
+
+ if (interrupt_critical_section_test_support_delay())
+ resets++;
+
+ out = DEADBEEF;
+ sc = rtems_event_receive(EVENTS, RTEMS_EVENT_ALL | RTEMS_WAIT, 1, &out);
+ rtems_test_assert(sc == RTEMS_TIMEOUT);
+ rtems_test_assert(out == DEADBEEF);
+
+ out = DEADBEEF;
+ sc = rtems_event_receive(EVENTS, RTEMS_EVENT_ALL | RTEMS_NO_WAIT, 0, &out);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+ rtems_test_assert(out == EVENTS);
+ }
+
+ sc = rtems_timer_cancel(ctx->timer);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ rtems_test_assert(ctx->hit);
+}
+
+static rtems_task Init(
+ rtems_task_argument ignored
+)
+{
+ rtems_status_code sc;
+ test_context ctx = {
+ .thread = _Thread_Executing
+ };
+
+ puts( "\n\n*** TEST INTERRUPT CRITICAL SECTION 10 ***" );
+
+ sc = rtems_timer_create(rtems_build_name('T', 'I', 'M', 'R'), &ctx.timer);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ test_any_satisfy_before_timeout(&ctx);
+ test_all_satisfy_before_timeout(&ctx);
+ test_timeout_before_all_satisfy(&ctx);
+
puts( "*** END OF TEST INTERRUPT CRITICAL SECTION 10 ***" );
rtems_test_exit(0);
}
@@ -61,5 +328,3 @@ rtems_task Init(
#define CONFIGURE_INIT
#include <rtems/confdefs.h>
-
-/* global variables */
diff --git a/testsuites/sptests/spintrcritical10/spintrcritical10.scn b/testsuites/sptests/spintrcritical10/spintrcritical10.scn
index 9f59c0e..e8db0c5 100644
--- a/testsuites/sptests/spintrcritical10/spintrcritical10.scn
+++ b/testsuites/sptests/spintrcritical10/spintrcritical10.scn
@@ -1,4 +1,5 @@
*** TEST INTERRUPT CRITICAL SECTION 10 ***
-Init - Test may not be able to detect case is hit reliably
-Init - Trying to generate timeout while blocking on event
+Init - Trying to generate any satisfied before timeout while blocking on event
+Init - Trying to generate all satisfied before timeout while blocking on event
+Init - Trying to generate timeout before all satisfied while blocking on event
*** END OF TEST INTERRUPT CRITICAL SECTION 10 ***
--
1.7.10.4
More information about the devel
mailing list