SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
copyrights:
- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
enabled-by: true
functional-type: action
links:
- role: requirement-refinement
uid: ../if/group
- role: validation
uid: flush-filter
- role: validation
uid: flush-remove-timer
- role: validation
uid: flush-unblock
post-conditions:
- name: Operation
states:
- name: Nop
test-code: |
/* Event receive */
i = 0;
T_eq_ptr( GetUnblock( ctx, &i )->thread, GetTCB( ctx, TQ_BLOCKER_A ) );
T_eq_ptr( GetUnblock( ctx, &i ), &T_scheduler_event_null );
text: |
No thread queue extraction operation shall be performed.
- name: ExtractAll
test-code: |
extracted_threads = CheckExtractions( ctx );
T_eq_sz( extracted_threads, ctx->tq_ctx->how_many );
text: |
The enqueued threads shall be extracted from the thread queue in
${/glossary/fifo:/term} order.
- name: ExtractPartial
test-code: |
extracted_threads = CheckExtractions( ctx );
T_lt_sz( extracted_threads, ctx->tq_ctx->how_many );
text: |
The enqueued threads which precede in ${/glossary/fifo:/term} order the
enqueued thread for which the flush filter returned ${/c/if/null:/name}
shall be extracted from the thread queue in ${/glossary/fifo:/term}
order.
test-epilogue: null
test-prologue: |
size_t i;
uint32_t extracted_threads;
pre-conditions:
- name: MayStop
states:
- name: 'Yes'
test-code: |
if ( !ctx->may_stop ) {
${.:skip}
}
text: |
Where the flush filter may return ${/c/if/null:/name}.
- name: 'No'
test-code: |
if ( ctx->may_stop ) {
${.:skip}
}
text: |
Where the flush filter does not return ${/c/if/null:/name}.
test-epilogue: null
test-prologue: null
- name: QueueEmpty
states:
- name: 'Yes'
test-code: |
ctx->tq_ctx->how_many = 0;
text: |
While the thread queue is empty.
- name: 'No'
test-code: |
ctx->tq_ctx->how_many = 3;
text: |
While the thread queue has at least one enqueued thread.
test-epilogue: null
test-prologue: null
- name: Stop
states:
- name: 'Yes'
test-code: |
ctx->stop = true;
text: |
While the flush filter returns ${/c/if/null:/name} for an enqueued
thread.
- name: 'No'
test-code: |
ctx->stop = false;
text: |
While the flush filter does not return ${/c/if/null:/name} for an
enqueued thread.
test-epilogue: null
test-prologue: null
- name: WaitState
states:
- name: Blocked
test-code: |
ctx->intend_to_block = false;
text: |
While the least recently enqueued thread on the thread queue is in the
blocked wait state.
- name: IntendToBlock
test-code: |
ctx->intend_to_block = true;
text: |
While the least recently enqueued thread on the thread queue is in the
intend to block wait state.
test-epilogue: null
test-prologue: null
rationale: null
references: []
requirement-type: functional
skip-reasons:
NoStop: |
The flush filter does not return ${/c/if/null:/name}.
test-action: |
uint32_t flush_count;
TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE_PREPARE );
if ( ctx->tq_ctx->how_many > 0 ) {
TQSend( ctx->tq_ctx, TQ_BLOCKER_B, TQ_EVENT_ENQUEUE );
TQSend( ctx->tq_ctx, TQ_BLOCKER_C, TQ_EVENT_ENQUEUE );
if ( ctx->intend_to_block ) {
T_scheduler_set_event_handler( SchedulerEvent, ctx );
}
TQSend( ctx->tq_ctx, TQ_BLOCKER_D, TQ_EVENT_ENQUEUE );
if ( !ctx->intend_to_block ) {
BlockerAFlush( ctx );
}
} else {
BlockerAFlush( ctx );
}
flush_count = ctx->tq_ctx->flush_count;
TQSchedulerRecordStop( ctx->tq_ctx );
TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_FLUSH_ALL );
TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE_DONE );
ctx->tq_ctx->flush_count = flush_count;
test-brief: null
test-cleanup: null
test-context:
- brief: |
If this member is true, then the flush filter shall return
${/c/if/null:/name}.
description: null
member: |
bool stop
- brief: |
If this member is true, then the least recently enqueued thread shall be in
the intend to block wait state.
description: null
member: |
bool intend_to_block
- brief: |
This member contains the call within ISR request.
description: null
member: |
CallWithinISRRequest request
test-context-support: null
test-description: null
test-header:
code: null
freestanding: false
includes: []
local-includes:
- tx-thread-queue.h
run-params:
- description: |
is the thread queue test context.
dir: inout
name: tq_ctx
specifier: TQContext *${.:name}
- description: |
is true, if a partial flush is supported.
dir: null
name: may_stop
specifier: bool ${.:name}
target: testsuites/validation/tr-tq-flush-fifo.h
test-includes: []
test-local-includes:
- tx-support.h
- tr-tq-flush-fifo.h
test-prepare: null
test-setup:
brief: null
code: |
ctx->request.arg = ctx;
TQReset( ctx->tq_ctx );
TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_A, PRIO_ULTRA_HIGH );
TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_B, PRIO_VERY_HIGH );
TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_C, PRIO_HIGH );
TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_D, PRIO_HIGH );
description: null
test-stop: null
test-support: |
typedef ${.:/test-context-type} Context;
static const T_scheduler_event *GetUnblock( Context *ctx, size_t *index )
{
return TQGetNextUnblock( ctx->tq_ctx, index );
}
static const rtems_tcb *GetTCB( Context *ctx, TQWorkerKind worker )
{
return ctx->tq_ctx->worker_tcb[ worker ];
}
static void BlockerAFlush( Context *ctx )
{
TQSchedulerRecordStart( ctx->tq_ctx );
if ( ctx->stop ) {
TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_FLUSH_PARTIAL );
} else {
TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_FLUSH_ALL );
}
}
static void InterruptFlush( void *arg )
{
Context *ctx;
ctx = arg;
TQSchedulerRecordStart( ctx->tq_ctx );
TQFlush( ctx->tq_ctx, !ctx->stop );
}
static void SchedulerEvent(
void *arg,
const T_scheduler_event *event,
T_scheduler_when when
)
{
Context *ctx;
ctx = arg;
if (
when == T_SCHEDULER_BEFORE &&
event->operation == T_SCHEDULER_BLOCK
) {
T_scheduler_set_event_handler( NULL, NULL );
ctx->request.handler = InterruptFlush;
CallWithinISRSubmit( &ctx->request );
}
}
static uint32_t CheckExtractions( Context *ctx )
{
uint32_t extracted_threads;
size_t i;
const T_scheduler_event *event;
extracted_threads = 0;
i = 0;
if ( !ctx->intend_to_block ) {
/* Event receive */
T_eq_ptr( GetUnblock( ctx, &i )->thread, GetTCB( ctx, TQ_BLOCKER_A ) );
}
event = GetUnblock( ctx, &i );
if ( event != &T_scheduler_event_null ) {
if ( ctx->intend_to_block ) {
T_eq_ptr( event->executing, NULL );
} else {
T_eq_ptr( event->executing, GetTCB( ctx, TQ_BLOCKER_A ) );
}
T_eq_ptr( event->thread, GetTCB( ctx, TQ_BLOCKER_B ) );
++extracted_threads;
}
event = GetUnblock( ctx, &i );
if ( event != &T_scheduler_event_null ) {
if ( ctx->intend_to_block ) {
T_eq_ptr( event->executing, NULL );
} else {
T_eq_ptr( event->executing, GetTCB( ctx, TQ_BLOCKER_A ) );
}
T_eq_ptr( event->thread, GetTCB( ctx, TQ_BLOCKER_C ) );
++extracted_threads;
}
event = GetUnblock( ctx, &i );
if ( event != &T_scheduler_event_null ) {
if ( ctx->intend_to_block ) {
T_eq_ptr( event->executing, GetTCB( ctx, TQ_BLOCKER_D ) );
} else {
T_eq_ptr( event->executing, GetTCB( ctx, TQ_BLOCKER_A ) );
}
T_eq_ptr( event->thread, GetTCB( ctx, TQ_BLOCKER_D ) );
++extracted_threads;
}
T_eq_ptr( GetUnblock( ctx, &i ), &T_scheduler_event_null );
T_eq_u32( extracted_threads, ctx->tq_ctx->flush_count );
return extracted_threads;
}
test-target: testsuites/validation/tr-tq-flush-fifo.c
test-teardown:
brief: null
code: |
TQReset( ctx->tq_ctx );
description: null
text: |
When the ${/glossary/fifo:/term} thread queue is flushed.
transition-map:
- enabled-by: true
post-conditions:
Operation: Nop
pre-conditions:
MayStop: all
QueueEmpty:
- 'Yes'
Stop: N/A
WaitState: N/A
- enabled-by: true
post-conditions:
Operation: ExtractAll
pre-conditions:
MayStop: all
QueueEmpty:
- 'No'
Stop:
- 'No'
WaitState: all
- enabled-by: true
post-conditions:
Operation: ExtractPartial
pre-conditions:
MayStop:
- 'Yes'
QueueEmpty:
- 'No'
Stop:
- 'Yes'
WaitState: all
- enabled-by: true
post-conditions: NoStop
pre-conditions:
MayStop:
- 'No'
QueueEmpty:
- 'No'
Stop:
- 'Yes'
WaitState: all
type: requirement