diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2022-08-31 07:44:29 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2022-08-31 10:35:26 +0200 |
commit | ad19d8420684c74deb5ef25a537d5e3ea0192325 (patch) | |
tree | 0a69a56aeb72d58d01299bfd11530ffed0593681 | |
parent | spec: Update due to API changes (diff) | |
download | rtems-central-ad19d8420684c74deb5ef25a537d5e3ea0192325.tar.bz2 |
spec: Move flush filter stop to flush fifo
This gets rid of a cyclic dependency in the specification graph.
-rw-r--r-- | spec/newlib/req/futex-wake.yml | 55 | ||||
-rw-r--r-- | spec/rtems/sem/req/flush.yml | 2 | ||||
-rw-r--r-- | spec/score/tq/req/flush-fifo.yml | 254 | ||||
-rw-r--r-- | spec/score/tq/req/flush-filter-stop.yml | 16 |
4 files changed, 232 insertions, 95 deletions
diff --git a/spec/newlib/req/futex-wake.yml b/spec/newlib/req/futex-wake.yml index 7a202d97..1a02a815 100644 --- a/spec/newlib/req/futex-wake.yml +++ b/spec/newlib/req/futex-wake.yml @@ -8,12 +8,8 @@ links: uid: ../if/futex-wake - role: function-implementation uid: /score/tq/req/flush-fifo -- role: function-implementation - uid: /score/tq/req/flush-filter-stop - role: requirement-refinement uid: futex -- role: validation - uid: /score/tq/req/flush-filter-stop post-conditions: - name: Result states: @@ -32,43 +28,28 @@ post-conditions: /* This state is checked by Enqueue() */ text: | No thread shall be extracted from the thread queue of the futex object. - - name: Partial + - name: 'Yes' test-code: | - /* This state is checked by Flush() */ + ${/score/tq/req/flush-fifo:/test-run}( &ctx->tq_ctx, true ); text: | The first count threads specified by the ``count`` parameter shall be extracted from the thread queue of the futex object in ${/glossary/fifo:/term} order. - - name: All - test-code: | - ${/score/tq/req/flush-fifo:/test-run}( &ctx->tq_ctx ); - text: | - All threads shall be extracted from the thread queue of the futex object - in ${/glossary/fifo:/term} order. test-epilogue: null test-prologue: null pre-conditions: - name: Count states: - - name: Negative + - name: NegativeOrZero test-code: | /* This state is prepared by Enqueue() */ text: | - While the ``count`` parameter is less than zero. - - name: Partial + While the ``count`` parameter is less or equal to than zero. + - name: Positive test-code: | /* This state is prepared by Flush() */ text: | - While the ``count`` parameter is greater than or equal to zero, - while the ``count`` parameter is less than the count of threads enqueued - on the thread queue of the futex object. - - name: All - test-code: | - /* This state is prepared by Flush() */ - text: | - While the ``count`` parameter is greater than or equal to zero, - while the ``count`` parameter is greater than or equal to the count of - threads enqueued on the thread queue of the futex object. + While the ``count`` parameter is greater than zero. test-epilogue: null test-prologue: null rationale: null @@ -155,20 +136,18 @@ test-support: | { Context *ctx; int count; - int how_many; - (void) all; + (void) thread_count; ctx = ToContext( tq_ctx ); - how_many = (int) ctx->tq_ctx.how_many; - - count = _Futex_Wake( &ctx->futex, 1 ); - T_eq_int( count, how_many > 0 ? 1 : 0 ); - count = _Futex_Wake( &ctx->futex, INT_MAX ); - T_eq_int( count, how_many > 1 ? how_many - 1 : 0 ); + if ( all ) { + count = _Futex_Wake( &ctx->futex, INT_MAX ); + } else { + count = _Futex_Wake( &ctx->futex, 1 ); + } - return thread_count; + return (uint32_t) count; } test-target: testsuites/validation/tc-futex-wake.c test-teardown: @@ -184,14 +163,12 @@ transition-map: Flush: 'No' pre-conditions: Count: - - Negative + - NegativeOrZero - enabled-by: true post-conditions: Result: Count - Flush: - - specified-by: Count + Flush: 'Yes' pre-conditions: Count: - - Partial - - All + - Positive type: requirement diff --git a/spec/rtems/sem/req/flush.yml b/spec/rtems/sem/req/flush.yml index f49310cc..ab8d86c9 100644 --- a/spec/rtems/sem/req/flush.yml +++ b/spec/rtems/sem/req/flush.yml @@ -31,7 +31,7 @@ post-conditions: ${../../status/if/not-defined:/name}. - name: FlushFIFO test-code: | - ${/score/tq/req/flush-fifo:/test-run}( &ctx->tq_ctx ); + ${/score/tq/req/flush-fifo:/test-run}( &ctx->tq_ctx, false ); text: | The calling task shall flush the semaphore as specified by ${/score/tq/req/flush-fifo}. diff --git a/spec/score/tq/req/flush-fifo.yml b/spec/score/tq/req/flush-fifo.yml index a318d74f..0b2621b7 100644 --- a/spec/score/tq/req/flush-fifo.yml +++ b/spec/score/tq/req/flush-fifo.yml @@ -18,76 +18,149 @@ post-conditions: - 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 operation shall be performed. - - name: TryExtract + No thread queue extraction operation shall be performed. + - name: ExtractAll test-code: | - event = GetUnblock( ctx, &i ); - T_eq_ptr( event->executing, NULL ); - T_eq_ptr( event->thread, GetTCB( ctx, TQ_BLOCKER_B ) ); - - event = GetUnblock( ctx, &i ); - T_eq_ptr( event->executing, NULL ); - T_eq_ptr( event->thread, GetTCB( ctx, TQ_BLOCKER_C ) ); - - event = GetUnblock( ctx, &i ); - T_eq_ptr( event->executing, GetTCB( ctx, TQ_BLOCKER_D ) ); - T_eq_ptr( event->thread, GetTCB( ctx, TQ_BLOCKER_D ) ); - - T_eq_ptr( GetUnblock( ctx, &i ), &T_scheduler_event_null ); + extracted_threads = CheckExtractions( ctx ); + T_eq_sz( extracted_threads, ctx->tq_ctx->how_many ); text: | - The enqueued threads of the thread queue may be extracted in + The enqueued threads shall be extracted from the thread queue in ${/glossary/fifo:/term} order. - test-epilogue: | + - 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; - const T_scheduler_event *event; - - i = 0; + size_t i; + uint32_t extracted_threads; pre-conditions: -- name: Queue +- name: MayStop states: - - name: Empty + - 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: NonEmpty + - 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: {} +skip-reasons: + NoStop: | + The flush filter does not return ${/c/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 ); - T_scheduler_set_event_handler( SchedulerEvent, ctx ); + + 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 { - TQSchedulerRecordStart( ctx->tq_ctx ); - TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_FLUSH_ALL ); + 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; + CallWithinISRRequest request test-context-support: null test-description: null test-header: @@ -102,6 +175,11 @@ test-header: 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: @@ -111,6 +189,7 @@ 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 ); @@ -131,13 +210,24 @@ test-support: | return ctx->tq_ctx->worker_tcb[ worker ]; } - static void Flush( void *arg ) + 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, true ); + TQFlush( ctx->tq_ctx, !ctx->stop ); } static void SchedulerEvent( @@ -154,12 +244,70 @@ test-support: | when == T_SCHEDULER_BEFORE && event->operation == T_SCHEDULER_BLOCK ) { - ctx->request.handler = Flush; - ctx->request.arg = ctx; - CallWithinISRSubmit( &ctx->request ); 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 @@ -173,12 +321,40 @@ transition-map: post-conditions: Operation: Nop pre-conditions: - Queue: - - Empty + MayStop: all + QueueEmpty: + - 'Yes' + Stop: N/A + WaitState: N/A - enabled-by: true post-conditions: - Operation: TryExtract + 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: - Queue: - - NonEmpty + MayStop: + - 'No' + QueueEmpty: + - 'No' + Stop: + - 'Yes' + WaitState: all type: requirement diff --git a/spec/score/tq/req/flush-filter-stop.yml b/spec/score/tq/req/flush-filter-stop.yml deleted file mode 100644 index f39a69ea..00000000 --- a/spec/score/tq/req/flush-filter-stop.yml +++ /dev/null @@ -1,16 +0,0 @@ -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 -links: -- role: requirement-refinement - uid: ../if/group -functional-type: function -rationale: null -references: [] -requirement-type: functional -text: | - When the caller provided filter handler returns a value equal to - ${/c/if/null:/name}, the thread queue flush operation shall stop extracting - threads from the thread queue. -type: requirement |