summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2021-09-17 15:07:36 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2021-09-24 12:02:01 +0200
commit04685dfcb8c1195b5878cb9ad1e457a3cca35d8a (patch)
treeb787fea98e4d8008ed7ac3a44375ecb62c229168
parentspec: Use T_now_tick() (diff)
downloadrtems-central-04685dfcb8c1195b5878cb9ad1e457a3cca35d8a.tar.bz2
spec: Specify priority change detail
-rw-r--r--spec/req/fine-grained-locking.yml15
-rw-r--r--spec/score/tq/req/lock.yml15
-rw-r--r--spec/score/tq/req/priority-change.yml16
-rw-r--r--spec/score/tq/val/smp.yml181
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