diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2021-09-20 12:37:23 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2021-09-24 13:13:51 +0200 |
commit | b3f558d74759f030f493fba5bace8e26c27835f4 (patch) | |
tree | 0228f58f3b94d12e28a33321cd4a05453057b07b | |
parent | spec: Improve deadlock specification (diff) | |
download | rtems-central-b3f558d74759f030f493fba5bace8e26c27835f4.tar.bz2 |
spec: Improve mutex try seize specification
-rw-r--r-- | spec/score/mtx/req/seize-try.yml | 492 | ||||
-rw-r--r-- | spec/score/status/if/unavailable.yml | 12 |
2 files changed, 353 insertions, 151 deletions
diff --git a/spec/score/mtx/req/seize-try.yml b/spec/score/mtx/req/seize-try.yml index fb7ad6ff..b8776566 100644 --- a/spec/score/mtx/req/seize-try.yml +++ b/spec/score/mtx/req/seize-try.yml @@ -11,54 +11,28 @@ post-conditions: states: - name: Ok test-code: | - T_eq_int( ctx->status, Status( ctx, STATUS_SUCCESSFUL ) ); - TQSurrender( &ctx->tq_ctx->base ); + T_true( IsEnqueueStatus( ctx, STATUS_SUCCESSFUL ) ); text: | The return status of the directive call shall be derived from ${../../status/if/successful:/name}. - - name: OkOrMutexCeilingViolated + - name: MutexCeilingViolated test-code: | - if ( ctx->tq_ctx->priority_ceiling != PRIO_INVALID ) { - T_eq_int( ctx->status, Status( ctx, STATUS_MUTEX_CEILING_VIOLATED ) ); - } else { - T_eq_int( ctx->status, Status( ctx, STATUS_SUCCESSFUL ) ); - TQSurrender( &ctx->tq_ctx->base ); - } + T_true( IsEnqueueStatus( ctx, STATUS_MUTEX_CEILING_VIOLATED ) ); text: | - Where the mutex provides a priority ceiling, the return status of the - directive call shall be derived from + The return status of the directive call shall be derived from ${../../status/if/mutex-ceiling-violated:/name}. - - Where the mutex does not provide a priority ceiling, the return status of - the directive call shall be derived from - ${../../status/if/successful:/name}. - - name: Recursive + - name: Deadlock test-code: | - switch ( ctx->tq_ctx->recursive ) { - case TQ_MTX_RECURSIVE_ALLOWED: - T_eq_int( ctx->status, Status( ctx, STATUS_SUCCESSFUL ) ); - TQSurrender( &ctx->tq_ctx->base ); - break; - case TQ_MTX_RECURSIVE_DEADLOCK: - T_eq_int( ctx->status, Status( ctx, STATUS_DEADLOCK ) ); - break; - default: - T_unreachable(); - break; - } + T_true( IsEnqueueStatus( ctx, STATUS_DEADLOCK ) ); text: | - Where recursive seize of the mutex is allowed, the return status of the - directive call shall be derived from ${../../status/if/successful:/name}. - - Where recursive seize of the mutex results in a deadlock, the return - status of the directive call shall be derived from + The return status of the directive call shall be derived from ${../../status/if/deadlock:/name}. - - name: Unsat + - name: Unavailable test-code: | - T_eq_int( ctx->status, Status( ctx, STATUS_UNSATISFIED ) ); + T_true( IsEnqueueStatus( ctx, STATUS_UNAVAILABLE ) ); text: | The return status of the directive call shall be derived from - ${../../status/if/unsatisfied:/name}. + ${../../status/if/unavailable:/name}. test-epilogue: null test-prologue: null - name: Owner @@ -67,32 +41,23 @@ post-conditions: test-code: | T_eq_ptr( ctx->owner_after, - ctx->tq_ctx->base.worker_tcb[ TQ_BLOCKER_A ] + ctx->tq_ctx->base.worker_tcb[ TQ_BLOCKER_B ] ); text: | The owner of the mutex shall not be modified. - name: Caller test-code: | - T_eq_ptr( ctx->owner_after, ctx->tq_ctx->base.runner_tcb ); - text: | - The owner of the mutex shall be the calling thread. - - name: CallerOrNoOwner - test-code: | - T_eq_ptr( ctx->owner_after, ctx->tq_ctx->base.runner_tcb ); + T_eq_ptr( + ctx->owner_after, + ctx->tq_ctx->base.worker_tcb[ TQ_BLOCKER_A ] + ); text: | The owner of the mutex shall be the calling thread. + - name: None test-code: | - if ( ctx->tq_ctx->priority_ceiling != PRIO_INVALID ) { - T_null( ctx->owner_after ); - } else { - T_eq_ptr( ctx->owner_after, ctx->tq_ctx->base.runner_tcb ); - } + T_null( ctx->owner_after ); text: | - Where the mutex provides a priority ceiling, the mutex shall have no - owner. - - Where the mutex does not provide a priority ceiling, the owner of the - mutex shall be the calling thread. + The mutex shall have no owner. test-epilogue: null test-prologue: null - name: Priority @@ -101,26 +66,93 @@ post-conditions: test-code: | T_eq_u32( ctx->priority_after, ctx->priority_before ); text: | - The current priority of the calling thread shall not be modified. + The priorities of the calling thread shall not be modified. + - name: Ceiling + test-code: | + T_eq_u32( ctx->priority_after, ctx->tq_ctx->priority_ceiling ); + text: | + The calling thread shall use the priority ceiling of the mutex. + test-epilogue: null + test-prologue: null +pre-conditions: +- name: Protocol + states: - name: Ceiling test-code: | + if ( + ctx->tq_ctx->priority_ceiling == PRIO_INVALID || + ctx->tq_ctx->base.enqueue_variant == TQ_ENQUEUE_STICKY + ) { + ${.:skip} + } + text: | + Where the mutex uses the priority ceiling locking protocol. + - name: MrsP + test-code: | + if ( + ctx->tq_ctx->priority_ceiling == PRIO_INVALID || + ctx->tq_ctx->base.enqueue_variant != TQ_ENQUEUE_STICKY + ) { + ${.:skip} + } + text: | + Where the mutex uses the MrsP locking protocol. + - name: Other + test-code: | if ( ctx->tq_ctx->priority_ceiling != PRIO_INVALID ) { - T_eq_u32( ctx->priority_after, ctx->tq_ctx->priority_ceiling ); - } else { - T_eq_u32( ctx->priority_after, ctx->priority_before ); + ${.:skip} } text: | - Where the mutex provides a priority ceiling, the calling thread shall use - the priority ceiling of the mutex. - - Where the mutex does not provide a priority ceiling, the current priority - of the calling thread shall not be modified. + Where the mutex does not use the priority ceiling or MrsP locking + protocol. + test-epilogue: null + test-prologue: null +- name: Discipline + states: + - name: FIFO + test-code: | + if ( ctx->tq_ctx->base.discipline != TQ_FIFO ) { + ${.:skip} + } + text: | + Where the thread queue of the mutex uses the FIFO discipline. + - name: Priority + test-code: | + if ( ctx->tq_ctx->base.discipline != TQ_PRIORITY ) { + ${.:skip} + } + text: | + Where the thread queue of the mutex uses the priority discipline. + test-epilogue: null + test-prologue: null +- name: Recursive + states: + - name: Allowed + test-code: | + if ( ctx->tq_ctx->recursive != TQ_MTX_RECURSIVE_ALLOWED ) { + ${.:skip} + } + text: | + Where a recursive seize of the mutex is allowed. + - name: Unavailable + test-code: | + if ( ctx->tq_ctx->recursive != TQ_MTX_RECURSIVE_UNAVAILABLE ) { + ${.:skip} + } + text: | + Where a recursive seize of the mutex results in an unavailable status. + - name: Deadlock + test-code: | + if ( ctx->tq_ctx->recursive != TQ_MTX_RECURSIVE_DEADLOCK ) { + ${.:skip} + } + text: | + Where a recursive seize of the mutex results in a deadlock status. test-epilogue: null test-prologue: null -pre-conditions: - name: Owner states: - - name: 'No' + - name: None test-code: | /* This is the default */ text: | @@ -139,24 +171,24 @@ pre-conditions: test-prologue: null - name: Priority states: - - name: LT + - name: High test-code: | ctx->priority_before = ctx->tq_ctx->priority_ceiling - 1; text: | - Where the mutex provides a priority ceiling, while the calling thread has - a ${/glossary/priority-current:/term} less than the priority ceiling. - - name: EQ + While the calling thread has a ${/glossary/priority-current:/term} higher + than the priority ceiling. + - name: Equal test-code: | ctx->priority_before = ctx->tq_ctx->priority_ceiling; text: | - Where the mutex provides a priority ceiling, while the calling thread has - a ${/glossary/priority-current:/term} equal to the priority ceiling. - - name: GT + While the calling thread has a ${/glossary/priority-current:/term} equal + to the priority ceiling. + - name: Low test-code: | ctx->priority_before = ctx->tq_ctx->priority_ceiling + 1; text: | - Where the mutex provides a priority ceiling, while the calling thread has - a ${/glossary/priority-current:/term} greater than the priority ceiling. + While the calling thread has a ${/glossary/priority-current:/term} lower + than the priority ceiling. test-epilogue: null test-prologue: null rationale: null @@ -165,68 +197,23 @@ requirement-type: functional skip-reasons: CeilingOwner: | Where the mutex provides a priority ceiling, the owner of the mutex cannot - have a ${/glossary/priority-current:/term} greater than the priority ceiling. + have a ${/glossary/priority-current:/term} lower than the priority ceiling. + PriorityDisciplineByProtocol: | + The priority ceiling and MrsP locking protocol requires a priority + discipline. test-action: | - rtems_task_priority priority; - - priority = GetSelfPriority(); - - if ( ctx->owner_caller ) { - Status_Control status; + TQSetScheduler( + &ctx->tq_ctx->base, + TQ_BLOCKER_B, + SCHEDULER_A_ID, + PRIO_VERY_HIGH + ); - status = TQEnqueue( &ctx->tq_ctx->base, TQ_NO_WAIT ); - T_eq_int( status, Status( ctx, STATUS_SUCCESSFUL ) ); - } else if ( ctx->owner_other ) { - if ( ctx->tq_ctx->base.enqueue_variant == TQ_ENQUEUE_STICKY ) { - TQSetScheduler( - &ctx->tq_ctx->base, - TQ_BLOCKER_A, - ctx->tq_ctx->base.other_scheduler_id, - PRIO_HIGH - ); - TQSend( - &ctx->tq_ctx->base, - TQ_BLOCKER_A, - TQ_EVENT_ENQUEUE | TQ_EVENT_RUNNER_SYNC - ); - TQSynchronizeRunner(); - } else { - TQSend( &ctx->tq_ctx->base, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE ); - } - } - - if ( ctx->tq_ctx->priority_ceiling != PRIO_INVALID ) { - SetSelfPriority( ctx->priority_before ); + if ( ctx->tq_ctx->base.enqueue_variant == TQ_ENQUEUE_STICKY ) { + ActionSticky( ctx ); } else { - ctx->priority_before = GetSelfPriority(); - } - - ctx->status = TQEnqueue( &ctx->tq_ctx->base, TQ_NO_WAIT ); - ctx->owner_after = TQGetOwner( &ctx->tq_ctx->base ); - ctx->priority_after = GetSelfPriority(); - - if ( ctx->owner_caller ) { - TQSurrender( &ctx->tq_ctx->base ); - } else if ( ctx->owner_other ) { - if ( ctx->tq_ctx->base.enqueue_variant == TQ_ENQUEUE_STICKY ) { - TQSend( - &ctx->tq_ctx->base, - TQ_BLOCKER_A, - TQ_EVENT_SURRENDER | TQ_EVENT_RUNNER_SYNC - ); - TQSynchronizeRunner(); - TQSetScheduler( - &ctx->tq_ctx->base, - TQ_BLOCKER_A, - ctx->tq_ctx->base.runner_scheduler_id, - PRIO_HIGH - ); - } else { - TQSend( &ctx->tq_ctx->base, TQ_BLOCKER_A, TQ_EVENT_SURRENDER ); - } + Action( ctx ); } - - SetSelfPriority( priority ); test-brief: null test-cleanup: null test-context: @@ -249,11 +236,6 @@ test-context: member: | rtems_task_priority priority_before; - brief: | - This member contains the return status of the directive call. - description: null - member: | - Status_Control status -- brief: | This member contains the owner of the mutex after the directive call. description: null member: | @@ -282,9 +264,14 @@ test-header: test-includes: [] test-local-includes: - tr-mtx-seize-try.h +- tr-tq-enqueue-ceiling.h +- tr-tq-enqueue-fifo.h +- tr-tq-enqueue-mrsp.h +- tr-tq-enqueue-priority.h test-prepare: | ctx->owner_caller = false; ctx->owner_other = false; + ctx->priority_before = PRIO_VERY_HIGH; test-setup: null test-stop: null test-support: | @@ -294,6 +281,104 @@ test-support: | { return TQConvertStatus( &ctx->tq_ctx->base, status ); } + + static bool IsEnqueueStatus( const Context *ctx, Status_Control expected ) + { + return ctx->tq_ctx->base.status[ TQ_BLOCKER_A ] == Status( ctx, expected ); + } + + static void Action( Context *ctx ) + { + TQSetScheduler( + &ctx->tq_ctx->base, + TQ_BLOCKER_A, + SCHEDULER_A_ID, + PRIO_VERY_HIGH + ); + + if ( ctx->owner_caller ) { + TQSend( &ctx->tq_ctx->base, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE ); + } else if ( ctx->owner_other ) { + TQSend( &ctx->tq_ctx->base, TQ_BLOCKER_B, TQ_EVENT_ENQUEUE ); + } + + TQSetPriority( &ctx->tq_ctx->base, TQ_BLOCKER_A, ctx->priority_before ); + TQSend( &ctx->tq_ctx->base, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE ); + ctx->owner_after = TQGetOwner( &ctx->tq_ctx->base ); + ctx->priority_after = TQGetPriority( &ctx->tq_ctx->base, TQ_BLOCKER_A ); + + if ( ctx->owner_caller ) { + TQSend( &ctx->tq_ctx->base, TQ_BLOCKER_A, TQ_EVENT_SURRENDER ); + } else if ( ctx->owner_other ) { + TQSend( &ctx->tq_ctx->base, TQ_BLOCKER_B, TQ_EVENT_SURRENDER ); + } + + if ( IsEnqueueStatus( ctx, STATUS_SUCCESSFUL ) ) { + TQSend( &ctx->tq_ctx->base, TQ_BLOCKER_A, TQ_EVENT_SURRENDER ); + } + } + + static void ActionSticky( Context *ctx ) + { + TQSetScheduler( + &ctx->tq_ctx->base, + TQ_BLOCKER_A, + SCHEDULER_B_ID, + PRIO_VERY_HIGH + ); + + if ( ctx->owner_caller ) { + TQSendAndSynchronizeRunner( + &ctx->tq_ctx->base, + TQ_BLOCKER_A, + TQ_EVENT_ENQUEUE + ); + } else if ( ctx->owner_other ) { + SetSelfScheduler( SCHEDULER_B_ID, PRIO_ULTRA_HIGH ); + TQSendAndSynchronizeRunner( + &ctx->tq_ctx->base, + TQ_BLOCKER_B, + TQ_EVENT_ENQUEUE + ); + SetSelfScheduler( SCHEDULER_A_ID, PRIO_ULTRA_HIGH ); + } + + TQSetPriority( &ctx->tq_ctx->base, TQ_BLOCKER_A, ctx->priority_before ); + TQClearDone( &ctx->tq_ctx->base, TQ_BLOCKER_A ); + TQSendAndWaitForExecutionStopOrIntendToBlock( + &ctx->tq_ctx->base, + TQ_BLOCKER_A, + TQ_EVENT_ENQUEUE + ); + ctx->owner_after = TQGetOwner( &ctx->tq_ctx->base ); + ctx->priority_after = TQGetPriority( &ctx->tq_ctx->base, TQ_BLOCKER_A ); + + if ( ctx->owner_caller ) { + TQSendAndSynchronizeRunner( + &ctx->tq_ctx->base, + TQ_BLOCKER_A, + TQ_EVENT_SURRENDER + ); + } else if ( ctx->owner_other ) { + SetSelfScheduler( SCHEDULER_B_ID, PRIO_ULTRA_HIGH ); + TQSendAndSynchronizeRunner( + &ctx->tq_ctx->base, + TQ_BLOCKER_B, + TQ_EVENT_SURRENDER + ); + SetSelfScheduler( SCHEDULER_A_ID, PRIO_NORMAL ); + } + + TQWaitForDone( &ctx->tq_ctx->base, TQ_BLOCKER_A ); + + if ( IsEnqueueStatus( ctx, STATUS_SUCCESSFUL ) ) { + TQSendAndSynchronizeRunner( + &ctx->tq_ctx->base, + TQ_BLOCKER_A, + TQ_EVENT_SURRENDER + ); + } + } test-target: testsuites/validation/tr-mtx-seize-try.c test-teardown: null text: | @@ -303,48 +388,153 @@ transition-map: post-conditions: Status: Ok Owner: Caller + Priority: Nop + pre-conditions: + Protocol: + - Other + Discipline: all + Recursive: all + Owner: + - None + Priority: N/A +- enabled-by: true + post-conditions: + Status: Ok + Owner: Caller Priority: Ceiling pre-conditions: + Protocol: + - Ceiling + - MrsP + Discipline: + - Priority + Recursive: all Owner: - - 'No' + - None Priority: - - EQ - - GT + - Low + - Equal - enabled-by: true post-conditions: - Status: OkOrMutexCeilingViolated - Owner: CallerOrNoOwner + Status: Unavailable + Owner: Other Priority: Nop pre-conditions: + Protocol: + - Other + Discipline: all + Recursive: all Owner: - - 'No' + - Other + Priority: N/A +- enabled-by: true + post-conditions: + Status: Unavailable + Owner: Other + Priority: Nop + pre-conditions: + Protocol: + - Ceiling + - MrsP + Discipline: all + Recursive: all + Owner: + - Other + Priority: all +- enabled-by: true + post-conditions: + Status: + - if: + pre-conditions: + Recursive: Allowed + then: Ok + - specified-by: Recursive + Owner: Caller + Priority: Nop + pre-conditions: + Protocol: + - Other + Discipline: all + Recursive: all + Owner: + - Caller + Priority: N/A +- enabled-by: true + post-conditions: + Status: Ok + Owner: Caller + Priority: Nop + pre-conditions: + Protocol: + - Ceiling + - MrsP + Discipline: + - Priority + Recursive: + - Allowed + Owner: + - Caller Priority: - - LT + - High + - Equal - enabled-by: true post-conditions: - Status: Recursive + Status: + - specified-by: Recursive Owner: Caller Priority: Nop pre-conditions: + Protocol: + - Ceiling + - MrsP + Discipline: + - Priority + Recursive: + - Deadlock + - Unavailable Owner: - Caller Priority: - - LT - - EQ + - High + - Equal - enabled-by: true post-conditions: - Status: Unsat - Owner: Other + Status: MutexCeilingViolated + Owner: None Priority: Nop pre-conditions: + Protocol: + - Ceiling + - MrsP + Discipline: + - Priority + Recursive: all Owner: - - Other - Priority: all + - None + Priority: + - High - enabled-by: true post-conditions: CeilingOwner pre-conditions: + Protocol: + - Ceiling + - MrsP + Discipline: + - Priority + Recursive: all Owner: - Caller Priority: - - GT + - Low +- enabled-by: true + post-conditions: PriorityDisciplineByProtocol + pre-conditions: + Protocol: + - Ceiling + - MrsP + Discipline: + - FIFO + Recursive: all + Owner: all + Priority: all type: requirement diff --git a/spec/score/status/if/unavailable.yml b/spec/score/status/if/unavailable.yml new file mode 100644 index 00000000..b7d76bdc --- /dev/null +++ b/spec/score/status/if/unavailable.yml @@ -0,0 +1,12 @@ +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 +index-entries: [] +interface-type: unspecified +links: +- role: interface-placement + uid: header +name: STATUS_UNAVAILABLE +references: [] +type: interface |