diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2021-09-17 15:07:36 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2021-09-24 12:02:01 +0200 |
commit | 04685dfcb8c1195b5878cb9ad1e457a3cca35d8a (patch) | |
tree | b787fea98e4d8008ed7ac3a44375ecb62c229168 | |
parent | spec: Use T_now_tick() (diff) | |
download | rtems-central-04685dfcb8c1195b5878cb9ad1e457a3cca35d8a.tar.bz2 |
spec: Specify priority change detail
-rw-r--r-- | spec/req/fine-grained-locking.yml | 15 | ||||
-rw-r--r-- | spec/score/tq/req/lock.yml | 15 | ||||
-rw-r--r-- | spec/score/tq/req/priority-change.yml | 16 | ||||
-rw-r--r-- | spec/score/tq/val/smp.yml | 181 |
4 files changed, 227 insertions, 0 deletions
diff --git a/spec/req/fine-grained-locking.yml b/spec/req/fine-grained-locking.yml new file mode 100644 index 00000000..9b25d37a --- /dev/null +++ b/spec/req/fine-grained-locking.yml @@ -0,0 +1,15 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: root +non-functional-type: design +rationale: null +references: [] +requirement-type: non-functional +text: | + If the system shall be implemented using fine grained locking at the lowest + level. +type: requirement diff --git a/spec/score/tq/req/lock.yml b/spec/score/tq/req/lock.yml new file mode 100644 index 00000000..3e3a76da --- /dev/null +++ b/spec/score/tq/req/lock.yml @@ -0,0 +1,15 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: requirement-refinement + uid: /req/fine-grained-locking +non-functional-type: design +rationale: null +references: [] +requirement-type: non-functional +text: | + The state of each thread queue object shall be protected by an + object-specific lock. +type: requirement diff --git a/spec/score/tq/req/priority-change.yml b/spec/score/tq/req/priority-change.yml new file mode 100644 index 00000000..a0d00d72 --- /dev/null +++ b/spec/score/tq/req/priority-change.yml @@ -0,0 +1,16 @@ +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: | + Where the thread queue uses a priority discipline, when the priority of an + enqueued thread changes, the position of the enqueued thread shall be changed + to reflect its new priority. +type: requirement diff --git a/spec/score/tq/val/smp.yml b/spec/score/tq/val/smp.yml new file mode 100644 index 00000000..365f07e2 --- /dev/null +++ b/spec/score/tq/val/smp.yml @@ -0,0 +1,181 @@ +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: RTEMS_SMP +links: [] +test-actions: +- action-brief: | + Create two worker threads and a mutex. Use the mutex and the worker to do + a thread priority change in parallel with a thread queue extraction. + action-code: | + SetSelfPriority( PRIO_NORMAL ); + _SMP_barrier_Control_initialize( &ctx->barrier ); + _SMP_barrier_State_initialize( &ctx->barrier_state ); + WrapThreadQueueInitialize( &ctx->wrap, Extract, ctx ); + + ctx->mutex_id = CreateMutex(); + ctx->thread_queue = GetMutexThreadQueue( ctx->mutex_id ); + checks: + - brief: | + Create and start worker A on a second processor. Let it obtain the + mutex. + code: | + ctx->worker_a_id = CreateTask( "WRKA", PRIO_NORMAL ); + SetScheduler( ctx->worker_a_id, SCHEDULER_B_ID, PRIO_NORMAL ); + StartTask( ctx->worker_a_id, WorkerA, ctx ); + + /* B0 */ + _SMP_barrier_Wait( &ctx->barrier, &ctx->barrier_state, 2 ); + links: [] + - brief: | + Create and start worker B. Let it try to obtain the mutex which is owned + by worker A. Delete worker B to extract it from the thread queue. Wrap + the thread queue extract operation to do a parallel thread priority + change carried out by worker A. + code: | + ctx->worker_b_id = CreateTask( "WRKB", PRIO_HIGH ); + StartTask( ctx->worker_b_id, WorkerB, ctx ); + WrapThreadQueueExtractDirect( &ctx->wrap, GetThread( ctx->worker_b_id ) ); + DeleteTask( ctx->worker_b_id ); + links: + - role: validation + uid: ../req/lock + - role: validation + uid: ../req/priority-change + - brief: | + Clean up all used resources. + code: | + /* B2 */ + _SMP_barrier_Wait( &ctx->barrier, &ctx->barrier_state, 2 ); + + DeleteTask( ctx->worker_a_id ); + DeleteMutex( ctx->mutex_id ); + WrapThreadQueueDestroy( &ctx->wrap ); + RestoreRunnerPriority(); + links: [] + links: [] +test-brief: | + Tests SMP-specific thread queue behaviour. +test-context: +- brief: | + This member contains the worker A identifier. + description: null + member: | + rtems_id worker_a_id +- brief: | + This member contains the worker B identifier. + description: null + member: | + rtems_id worker_b_id +- brief: | + This member contains the mutex identifier. + description: null + member: | + rtems_id mutex_id +- brief: | + This member contains the thread queue of the mutex. + description: null + member: | + Thread_queue_Queue *thread_queue +- brief: | + This member contains the context to wrap the thread queue extract. + description: null + member: | + WrapThreadQueueContext wrap +- brief: | + This member contains the barrier to synchronize the runner, worker A, and + worker B. + description: null + member: | + SMP_barrier_Control barrier +- brief: | + This member contains the barrier state for the runner processor. + description: null + member: | + SMP_barrier_State barrier_state +test-context-support: null +test-description: null +test-header: null +test-includes: +- rtems/score/smpbarrier.h +- rtems/score/threadq.h +test-local-includes: +- tx-support.h +test-setup: null +test-stop: null +test-support: | + typedef ${.:/test-context-type} Context; + + static void Extract( void *arg ) + { + Context *ctx; + unsigned int ticket_0; + unsigned int ticket_1; + + ctx = arg; + + ticket_0 = _Atomic_Load_uint( + &ctx->thread_queue->Lock.next_ticket, + ATOMIC_ORDER_RELAXED + ); + + /* B1 */ + _SMP_barrier_Wait( &ctx->barrier, &ctx->barrier_state, 2 ); + + /* + * Ensure that worker A acquired the thread wait lock of worker B. + */ + do { + ticket_1 = _Atomic_Load_uint( + &ctx->thread_queue->Lock.next_ticket, + ATOMIC_ORDER_RELAXED + ); + } while ( ticket_0 == ticket_1 ); + + /* + * Continue with the thread queue extraction. The thread wait lock of + * worker B will be changed back to the default thread wait lock. This + * will cause worker A to release the thread queue lock and acquire the + * default thread wait lock of worker B instead to carry out the priority + * change. + * + * See also _Thread_Wait_acquire_critical(). + */ + } + + static void WorkerA( rtems_task_argument arg ) + { + Context *ctx; + SMP_barrier_State state; + + ctx = (Context *) arg; + _SMP_barrier_State_initialize( &state ); + + ObtainMutex( ctx->mutex_id ); + + /* B0 */ + _SMP_barrier_Wait( &ctx->barrier, &state, 2 ); + + /* B1 */ + _SMP_barrier_Wait( &ctx->barrier, &state, 2 ); + + SetPriority( ctx->worker_b_id, PRIO_VERY_HIGH ); + ReleaseMutex( ctx->mutex_id ); + + /* B2 */ + _SMP_barrier_Wait( &ctx->barrier, &state, 2 ); + + SuspendSelf(); + } + + static void WorkerB( rtems_task_argument arg ) + { + Context *ctx; + + ctx = (Context *) arg; + + ObtainMutex( ctx->mutex_id ); + } +test-target: testsuites/validation/tc-score-tq-smp.c +test-teardown: null +type: test-case |