mirror of
https://github.com/t-crest/rtems.git
synced 2025-11-16 12:34:47 +00:00
rtems: Critical fix for events
Commit 4b45c1393c marked a test in
_Event_Timeout() as debug only. This test is required also in non-debug
configurations since otherwise state corruption can happen. A revised
test sptests/spintrcritical10 checks the relevant sequences.
This commit is contained in:
@@ -64,13 +64,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 ) ) {
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
* COPYRIGHT (c) 1989-2009.
|
||||
* 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.
|
||||
@@ -9,36 +11,308 @@
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1
|
||||
#include <tmacros.h>
|
||||
#include <intrcritical.h>
|
||||
|
||||
rtems_id Main_task;
|
||||
#define GREEN RTEMS_EVENT_0
|
||||
|
||||
rtems_task Init(
|
||||
#define RED RTEMS_EVENT_1
|
||||
|
||||
#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;
|
||||
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 == 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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
sc = rtems_timer_fire_after(ctx->timer, 1, all_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_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;
|
||||
rtems_event_set out;
|
||||
int resets;
|
||||
rtems_status_code sc;
|
||||
test_context ctx = {
|
||||
.thread = _Thread_Executing
|
||||
};
|
||||
|
||||
puts( "\n\n*** TEST INTERRUPT CRITICAL SECTION 10 ***" );
|
||||
|
||||
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_create(rtems_build_name('T', 'I', 'M', 'R'), &ctx.timer);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
Main_task = rtems_task_self();
|
||||
|
||||
interrupt_critical_section_test_support_initialize( NULL );
|
||||
|
||||
for (resets=0 ; resets< 2 ;) {
|
||||
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" );
|
||||
}
|
||||
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);
|
||||
@@ -56,5 +330,3 @@ rtems_task Init(
|
||||
|
||||
#define CONFIGURE_INIT
|
||||
#include <rtems/confdefs.h>
|
||||
|
||||
/* global variables */
|
||||
|
||||
@@ -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 ***
|
||||
|
||||
Reference in New Issue
Block a user