[rtems-central commit] spec: Partially specify message manager

Sebastian Huber sebh at rtems.org
Thu Sep 2 11:31:20 UTC 2021


Module:    rtems-central
Branch:    master
Commit:    9f4f0ce9f9b57bb4422f845fd7507d5a01e8bde3
Changeset: http://git.rtems.org/rtems-central/commit/?id=9f4f0ce9f9b57bb4422f845fd7507d5a01e8bde3

Author:    Frank Kühndel <frank.kuehndel at embedded-brains.de>
Date:      Thu Aug 19 15:20:16 2021 +0200

spec: Partially specify message manager

---

 spec/rtems/message/glossary/firstmessage.yml       |   36 +
 spec/rtems/message/glossary/lastmessage.yml        |   12 +
 spec/rtems/message/glossary/maximummessagesize.yml |   16 +
 .../message/glossary/maximumpendingmessages.yml    |   16 +
 spec/rtems/message/glossary/nop.yml                |   14 +
 spec/rtems/message/glossary/receiver.yml           |   17 +
 spec/rtems/message/req/attributes.yml              |   18 +
 spec/rtems/message/req/buffer.yml                  |   28 +
 spec/rtems/message/req/options.yml                 |   15 +
 spec/rtems/message/req/receive.yml                 | 1061 ++++++++++++++++++++
 spec/rtems/message/req/urgent-send.yml             |  758 ++++++++++++++
 spec/rtems/message/val/message-macros.yml          |  120 +++
 12 files changed, 2111 insertions(+)

diff --git a/spec/rtems/message/glossary/firstmessage.yml b/spec/rtems/message/glossary/firstmessage.yml
new file mode 100644
index 0000000..d206665
--- /dev/null
+++ b/spec/rtems/message/glossary/firstmessage.yml
@@ -0,0 +1,36 @@
+SPDX-License-Identifier: CC-BY-SA-4.0
+copyrights:
+- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
+enabled-by: true
+glossary-type: term
+links:
+- role: glossary-member
+  uid: /glossary-requirements
+term: First message
+text: |
+  Messages are stored - and kept - in a ${/glossary/messagequeue:/term}
+  in a defined order: Mgs[0], Mgs[1], Mgs[2] till Msg[N-1] when N
+  messages are in the queue. Mgs[0] is named the *first message*.  Msg[N-1]
+  is named the *last message*.
+
+  ${../if/receive:/name} returns the first message (if the
+  ${/glossary/messagequeue:/term} is not empty).  The
+  receive operation removes the first message (Msg[0]) from the queue
+  so that N-1 messages are in the queue.  The remaining messages change
+  place so that "old" message Msg[i] becomes "new" Msg[i-1].
+
+  Messages are stored by ${../if/send:/name} in a
+  ${/glossary/messagequeue:/term} in {/glossary/fifo:/term} order
+  (if no ${../if/receive:/name} directive is waiting to receive a
+  message).  ${../if/send:/name} adds the message as "new" last message
+  Msg[N] to the queue and the number of messages in the queue increases
+  by one: N+1.
+
+  In contrast, messages are stored by ${../if/urgent:/name} in a
+  ${/glossary/messagequeue:/term} in {/glossary/lifo:/term} order
+  (if no ${../if/receive:/name} directive is waiting to receive a
+  message).  ${../if/urgent:/name} adds the message as "new" first message
+  Msg[0] to the queue. The messages which have been in the queue before
+  change place so that "old" message Msg[i] becomes "new" Msg[i+1] and the
+  number of messages in the queue increases by one: N+1.
+type: glossary
diff --git a/spec/rtems/message/glossary/lastmessage.yml b/spec/rtems/message/glossary/lastmessage.yml
new file mode 100644
index 0000000..7364234
--- /dev/null
+++ b/spec/rtems/message/glossary/lastmessage.yml
@@ -0,0 +1,12 @@
+SPDX-License-Identifier: CC-BY-SA-4.0
+copyrights:
+- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
+enabled-by: true
+glossary-type: term
+links:
+- role: glossary-member
+  uid: /glossary-requirements
+term: Last message
+text: |
+  See ${../glossary/firstmessage:/term}.
+type: glossary
diff --git a/spec/rtems/message/glossary/maximummessagesize.yml b/spec/rtems/message/glossary/maximummessagesize.yml
new file mode 100644
index 0000000..9e0afb2
--- /dev/null
+++ b/spec/rtems/message/glossary/maximummessagesize.yml
@@ -0,0 +1,16 @@
+SPDX-License-Identifier: CC-BY-SA-4.0
+copyrights:
+- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
+enabled-by: true
+glossary-type: term
+links:
+- role: glossary-member
+  uid: /glossary-requirements
+term: maximum message size
+text: |
+  The maximum message size is different for each
+  ${/glossary/messagequeue:/term} but equal for all directives called
+  on the same ${/glossary/messagequeue:/term}.  It is defined by
+  the value of member ${../if/config:/definition[2]/default/name} of type
+  ${../if/config:/name} used to construct the ${/glossary/messagequeue:/term}.
+type: glossary
diff --git a/spec/rtems/message/glossary/maximumpendingmessages.yml b/spec/rtems/message/glossary/maximumpendingmessages.yml
new file mode 100644
index 0000000..c770289
--- /dev/null
+++ b/spec/rtems/message/glossary/maximumpendingmessages.yml
@@ -0,0 +1,16 @@
+SPDX-License-Identifier: CC-BY-SA-4.0
+copyrights:
+- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
+enabled-by: true
+glossary-type: term
+links:
+- role: glossary-member
+  uid: /glossary-requirements
+term: maximum pending messages
+text: |
+  The maximum of pending messages is different for each
+  ${/glossary/messagequeue:/term} but equal for all directives called
+  on the same ${/glossary/messagequeue:/term}.  It is defined by
+  the value of member ${../if/config:/definition[1]/default/name} of type
+  ${../if/config:/name} used to construct the ${/glossary/messagequeue:/term}.
+type: glossary
diff --git a/spec/rtems/message/glossary/nop.yml b/spec/rtems/message/glossary/nop.yml
new file mode 100644
index 0000000..372e356
--- /dev/null
+++ b/spec/rtems/message/glossary/nop.yml
@@ -0,0 +1,14 @@
+SPDX-License-Identifier: CC-BY-SA-4.0
+copyrights:
+- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
+enabled-by: true
+glossary-type: term
+links:
+- role: glossary-member
+  uid: /glossary-requirements
+term: Nop
+text: |
+  Nop means *no operation*.  This term is used when directives do not return
+  ${../../status/if/successful:/name} as result.  Nop indicates that the call of
+  a directive has no observable effect on any ${/glossary/rtems:/term} state.
+type: glossary
diff --git a/spec/rtems/message/glossary/receiver.yml b/spec/rtems/message/glossary/receiver.yml
new file mode 100644
index 0000000..f50fbec
--- /dev/null
+++ b/spec/rtems/message/glossary/receiver.yml
@@ -0,0 +1,17 @@
+SPDX-License-Identifier: CC-BY-SA-4.0
+copyrights:
+- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
+enabled-by: true
+glossary-type: term
+links:
+- role: glossary-member
+  uid: /glossary-requirements
+term: Receiver
+text: |
+  In this particular case, *receiver* shall be a task which invoked
+  directive ${../if/receice:/name} on the empty ${/glossary/messagequeue:/term}
+  with ${../if/receive:/params[3]/name} set to ${../../option/if/wait:/name}
+  and which is still waiting to receive a message when a
+  ${../if/send:/name} or ${../if/urgent:/name} directive is invoked on
+  that ${/glossary/messagequeue:/term}.
+type: glossary
diff --git a/spec/rtems/message/req/attributes.yml b/spec/rtems/message/req/attributes.yml
new file mode 100644
index 0000000..5e9ecdf
--- /dev/null
+++ b/spec/rtems/message/req/attributes.yml
@@ -0,0 +1,18 @@
+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: ../../attr/if/default
+non-functional-type: interface
+rationale: null
+references: []
+requirement-type: non-functional
+text: |
+  The value of macro ${../../attr/if/default:/name} shall be equal to the value
+  of the expression ``RTEMS_FIFO | RTEMS_LOCAL``.
+
+  Note: ${../../attr/if/global:/name} is not part of the space profile
+  because no remote ${/glossary/node:/plural} are supported.
+type: requirement
diff --git a/spec/rtems/message/req/buffer.yml b/spec/rtems/message/req/buffer.yml
new file mode 100644
index 0000000..575434d
--- /dev/null
+++ b/spec/rtems/message/req/buffer.yml
@@ -0,0 +1,28 @@
+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: ../if/buffer
+non-functional-type: interface
+rationale: null
+references: []
+requirement-type: non-functional
+text: |
+  When argument ${../if/buffer:/params[0]/name} is the size of
+  the largest possible message in bytes
+  (the same value as member ${../if/config:/definition[2]/name} of type
+  ${../if/config:/name}),
+  and ``MAXIMUM_PENDING_MESSAGES`` is the maximum number of messages
+  which can be stored in the message queue
+  (the same value as member ${../if/config:/definition[1]/name} of type
+  ${../if/config:/name}),
+  and ``storage_area`` is a variable or structure member,
+  the expression
+  ``${../if/buffer:/name}(`` ``${../if/buffer:/params[0]/name} )``
+  ``storage_area[`` ``MAXIMUM_PENDING_MESSAGES ]``
+  shall declare an object of such a size that a pointer to it
+  is usable as value for member ${../if/config:/definition[3]/name}
+  of type ${../if/config:/name}.
+type: requirement
diff --git a/spec/rtems/message/req/options.yml b/spec/rtems/message/req/options.yml
new file mode 100644
index 0000000..a0fe5a0
--- /dev/null
+++ b/spec/rtems/message/req/options.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: ../../option/if/default
+non-functional-type: interface
+rationale: null
+references: []
+requirement-type: non-functional
+text: |
+  The value of macro ${../../option/if/default:/name} shall be equal
+  to the value of the expression ``RTEMS_WAIT``.
+type: requirement
diff --git a/spec/rtems/message/req/receive.yml b/spec/rtems/message/req/receive.yml
new file mode 100644
index 0000000..ce20d33
--- /dev/null
+++ b/spec/rtems/message/req/receive.yml
@@ -0,0 +1,1061 @@
+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: interface-function
+  uid: ../if/receive
+post-conditions:
+- name: Status
+  states:
+  - name: Ok
+    test-code: |
+      T_rsc_success( ctx->status );
+    text: |
+      The return status of ${../if/receive:/name} shall be
+      ${../../status/if/successful:/name}
+  - name: InvId
+    test-code: |
+      T_rsc( ctx->status, RTEMS_INVALID_ID );
+    text: |
+      The return status of ${../if/receive:/name} shall be
+      ${../../status/if/invalid-id:/name}.
+  - name: InvAddr
+    test-code: |
+      T_rsc( ctx->status, RTEMS_INVALID_ADDRESS );
+    text: |
+      The return status of ${../if/receive:/name} shall be
+      ${../../status/if/invalid-address:/name}.
+  - name: Unsat
+    test-code: |
+      T_rsc( ctx->status, RTEMS_UNSATISFIED  );
+    text: |
+      The return status of ${../if/receive:/name} shall be
+      ${../../status/if/unsatisfied:/name}.
+  - name: Timeout
+    test-code: |
+      T_rsc( ctx->status, RTEMS_TIMEOUT );
+    text: |
+      The return status of ${../if/receive:/name} shall be
+      ${../../status/if/timeout:/name}.
+  - name: Deleted
+    test-code: |
+      T_rsc( ctx->status, RTEMS_OBJECT_WAS_DELETED );
+    text: |
+      The return status of ${../if/receive:/name} shall be
+      ${../../status/if/object-was-deleted:/name}.
+  test-epilogue: null
+  test-prologue: null
+- name: Delay
+  states:
+  - name: None
+    test-code: |
+      T_eq_u32( ctx->action_duration, 0 );
+    text: |
+      The ${../if/receive:/name} call shall return immediately.
+  - name: Ticks
+    test-code: |
+      T_eq_u32( ctx->action_duration, timeout_ticks );
+    text: |
+      The ${../if/receive:/name} call shall return after the timeout
+      period in ticks.
+  - name: Forever
+    test-code: |
+      T_gt_u32( ctx->action_duration, timeout_ticks );
+    text: |
+      The ${../if/receive:/name} call shall not return.
+  test-epilogue: null
+  test-prologue: null
+- name: Size
+  states:
+  - name: First
+    test-code: |
+      CheckForFirstMessage(
+        ctx->status,
+        ctx->receive_buffer,
+        ctx->receive_size
+      );
+    text: |
+      The value of the object referenced by the
+      ${../if/receive:/params[2]/name} parameter shall be set to the size of
+      the ${../glossary/firstmessage:/term} (the same value as provided by
+      parameter ${../if/send:/params[2]/name} of the ${../if/send:/name}
+      or ${../if/urgent:/name} directive which added the message to
+      the queue) after the return of the ${../if/receive:/name} call.
+  - name: Nop
+    test-code: |
+      T_eq_sz( ctx->receive_size, SIZE_MAX );
+    text: |
+      Objects referenced by the ${../if/receive:/params[2]/name}
+      parameter in past calls to ${../if/receive:/name} shall not be
+      accessed by the ${../if/receive:/name} call (see also
+      ${../glossary/nop:/term}).
+  test-epilogue: null
+  test-prologue: null
+- name: Msg
+  states:
+  - name: First
+    test-code: |
+      CheckForFirstMessage(
+        ctx->status,
+        ctx->receive_buffer,
+        ctx->receive_size
+      );
+    text: |
+      The bytes 0 till ${../if/receive:/params[2]/name} - 1 of the object
+      referenced by the ${../if/receive:/params[3]/name} parameter shall
+      contain a copy of the content of the ${../glossary/firstmessage:/term}
+      (all bytes unchanged and in the same order as provided
+      by parameter ${../if/send:/params[1]/name} of the
+      ${../if/send:/name} or ${../if/urgent:/name} directive which added
+      the message to the queue) after the return of the
+      ${../if/receive:/name} call.
+  - name: Nop
+    test-code: |
+      int i;
+      for ( i = 0; i < MAXIMUM_MESSAGE_SIZE; ++i ) {
+        T_eq_u8( ctx->receive_buffer[i], UINT8_MAX );
+      }
+    text: |
+      Objects referenced by the ${../if/receive:/params[3]/name}
+      parameter in past calls to ${../if/receive:/name} shall not be
+      accessed by the ${../if/receive:/name} call (see also
+      ${../glossary/nop:/term}).
+  test-epilogue: null
+  test-prologue: null
+- name: MsgQueue
+  states:
+  - name: Empty
+    test-code: |
+      PopMessage( ctx, CheckForNoMessage );
+    text: |
+      The ${/glossary/messagequeue:/term} shall be empty after the
+      return of the ${../if/receive:/name} call.
+  - name: OneLess
+    test-code: |
+      PopMessage( ctx, CheckForSecondMessage );
+      PopMessage( ctx, CheckForThirdMessage );
+      PopMessage( ctx, CheckForNoMessage );
+    text: |
+      The ${../glossary/firstmessage:/term} shall be removed from the
+      ${/glossary/messagequeue:/term} after the
+      return of the ${../if/receive:/name} call.
+  - name: Nop
+    test-code: |
+      ctx->check_msgq_unchanged( ctx );
+    text: |
+      Objects referenced by the ${../if/receive:/params[0]/name}
+      parameter in past calls to ${../if/receive:/name} shall not be
+      accessed by the ${../if/receive:/name} call (see also
+      ${../glossary/nop:/term}).
+  test-epilogue: |
+    MessageQueueTeardown( ctx );
+  test-prologue: null
+- name: Tasks
+  states:
+  - name: Fifo
+    test-code: |
+      ${/score/tq/req/enqueue-fifo:/test-run}( &ctx->tq_ctx );
+    text: |
+      Where the thread queue uses the FIFO discipline, the calling thread shall
+      be enqueued in FIFO order.
+  - name: Priority
+    test-code: |
+      ${/score/tq/req/enqueue-priority:/test-run}( &ctx->tq_ctx );
+    text: |
+      Where the thread queue uses the priority discipline, the calling thread
+      shall be enqueued in priority order.
+  test-epilogue: |
+    MessageQueueTeardown( ctx );
+  test-prologue: |
+    MessageQueueSetup( ctx );
+pre-conditions:
+- name: Buffer
+  states:
+  - name: Valid
+    test-code: |
+      ctx->buffer_param = ctx->receive_buffer;
+    text: |
+      While the ${../if/receive:/params[1]/name} parameter references a memory
+      area able to store a message up to the maximum size permitted in this
+      ${/glossary/messagequeue:/term}.
+  - name: 'Null'
+    test-code: |
+      ctx->buffer_param = NULL;
+    text: |
+      While the ${../if/receive:/params[1]/name} parameter is
+      ${/c/if/null:/name}.
+  test-epilogue: null
+  test-prologue: null
+- name: Size
+  states:
+  - name: Valid
+    test-code: |
+      ctx->size_param = &ctx->receive_size;
+    text: |
+      While the ${../if/receive:/params[2]/name} parameter references an object
+      of type ``size_t``.
+  - name: 'Null'
+    test-code: |
+      ctx->size_param = NULL;
+    text: |
+      While the ${../if/receive:/params[2]/name} parameter is
+      ${/c/if/null:/name}.
+  test-epilogue: null
+  test-prologue: null
+- name: Id
+  states:
+  - name: Valid
+    test-code: |
+      ctx->id_param = 1;
+    text: |
+      While the ${../if/receive:/params[0]/name} parameter is valid.
+  - name: Invalid
+    test-code: |
+      ctx->id_param = RTEMS_ID_NONE;
+    text: |
+      While the ${../if/receive:/params[0]/name} parameter is invalid.
+  test-epilogue: null
+  test-prologue: null
+- name: DuringWait
+  states:
+  - name: Nop
+    test-code: |
+      ctx->concurrent_activity = MessageQueueNop;
+    text: |
+      While no ${../if/delete:/name} directive is called successfully
+      on the ${/glossary/messagequeue:/term} during the time one or more
+      ${/glossary/task:/plural} are waiting to receive messages.
+  - name: Deleted
+    test-code: |
+      ctx->concurrent_activity = MessageQueueDelete;
+    text: |
+      While ${../if/delete:/name} is called successfully on the
+      ${/glossary/messagequeue:/term} while one or more
+      ${/glossary/task:/plural} are waiting to receive messages.
+  test-epilogue: null
+  test-prologue: null
+- name: TaskQueue
+  states:
+  - name: Fifo
+    test-code:  |
+      ctx->attribute_set = RTEMS_LOCAL | RTEMS_FIFO;
+    text: |
+      While the member ${../if/config:/definition[6]/default/name} of type
+      ${../if/config:/name} contains value ${../../attr/if/fifo:/name}
+      when the ${/glossary/messagequeue:/term} is constructed.
+
+      Note: ${../../attr/if/global:/name} is not part of the space profile
+      because no remote ${/glossary/node:/plural} are supported.
+  - name: Priority
+    test-code: |
+      ctx->attribute_set = RTEMS_LOCAL | RTEMS_PRIORITY;
+    text: |
+      While the member ${../if/config:/definition[6]/default/name} of type
+      ${../if/config:/name} contains value ${../../attr/if/priority:/name}
+      when the ${/glossary/messagequeue:/term} is constructed.
+
+      Note: ${../../attr/if/global:/name} is not part of the space profile
+      because no remote ${/glossary/node:/plural} are supported.
+  test-epilogue: |
+    MessageQueueSetup( ctx );
+  test-prologue: null
+- name: Wait
+  states:
+  - name: 'No'
+    test-code: |
+      ctx->tq_ctx.wait =      TQ_NO_WAIT;
+      ctx->option_set_param = RTEMS_NO_WAIT;
+      ctx->timeout_param =    1; /* 0 would be RTEMS_NO_TIMEOUT */
+    text: |
+      While the ${../if/receive:/params[3]/name} parameter indicates the
+      ${../../option/if/no-wait:/name} option.
+  - name: Timeout
+    test-code: |
+      ctx->tq_ctx.wait =      TQ_WAIT_TICKS;
+      ctx->option_set_param = RTEMS_WAIT;
+      ctx->timeout_param =    timeout_ticks;
+    text: |
+      While the ${../if/receive:/params[3]/name} parameter indicates the
+      ${../../option/if/wait:/name} option, while the
+      ${../if/receive:/params[4]/name} parameter is not equal to
+      ${../../type/if/no-timeout:/name}.
+  - name: Forever
+    test-code: |
+      ctx->tq_ctx.wait =      TQ_WAIT_FOREVER;
+      ctx->option_set_param = RTEMS_WAIT;
+      ctx->timeout_param =    RTEMS_NO_TIMEOUT;
+    text: |
+      While the ${../if/receive:/params[3]/name} parameter indicates the
+      ${../../option/if/wait:/name} option, while the
+      ${../if/receive:/params[4]/name} parameter is equal to
+      ${../../type/if/no-timeout:/name}.
+  test-epilogue: null
+  test-prologue: null
+- name: MsgQueue
+  states:
+  - name: Empty
+    test-code: |
+      /* Message queue is already empty. */
+      ctx->check_msgq_unchanged = CheckForNoMessageInQueue;
+    text: |
+      While there is no message in the ${/glossary/messagequeue:/term}.
+  - name: One
+    test-code: |
+      SendMsg( &( ctx->tq_ctx ) );
+      ctx->check_msgq_unchanged = CheckForOneMessageInQueue;
+    text: |
+      While there is exactly one message in the ${/glossary/messagequeue:/term}.
+  - name: Several
+    test-code: |
+      SendMsg( &( ctx->tq_ctx ) );
+      SendMsg( &( ctx->tq_ctx ) );
+      SendMsg( &( ctx->tq_ctx ) );
+      ctx->check_msgq_unchanged = CheckForSeveralMessagesInQueue;
+    text: |
+      While there are more than one message in the
+      ${/glossary/messagequeue:/term}.
+  test-epilogue: null
+  test-prologue: null
+- name: Storage
+  states:
+  - name: Nop
+    test-code: |
+      /* Only a requirement text. */
+    text: |
+      While the memory area to which a pointer is provided as member
+      ${../if/config:/definition[3]/default/name} of type
+      ${../if/config:/name} when the ${/glossary/messagequeue:/term} is
+      constructed by ${../if/construct:/name} is altered only by the
+      RTEMS operating system.
+  test-epilogue: null
+  test-prologue: null
+rationale: null
+references: []
+requirement-type: functional
+skip-reasons:
+  NoWait: |
+    The case *Deleted* can only occur when at least one
+    ${../if/receive:/name} call is waiting on an empty
+    ${/glossary/messagequeue:/term}.
+test-action: |
+  WorkerDoAction( ctx );
+  ctx->concurrent_activity( ctx );
+  ctx->action_duration = WaitForWorker( ctx );
+test-brief: null
+test-cleanup: null
+test-context:
+- brief: |
+    This member contains the thread queue test context.
+  description: null
+  member: |
+    TQContext tq_ctx
+- brief: |
+    This member specifies the attribute set of the
+    ${/glossary/messagequeue:/term}.
+  description: null
+  member: |
+    rtems_attribute attribute_set
+- brief: |
+    This member is used as storage area for the
+    ${/glossary/messagequeue:/term}.
+  description: null
+  member: |
+    RTEMS_MESSAGE_QUEUE_BUFFER( MAXIMUM_MESSAGE_SIZE )
+      storage_area[ MAXIMUM_PENDING_MESSAGES]
+- brief: |
+    This member contains always the same arbitrary number ``magic``.
+  description: |
+    It is used for run-time type checking.
+  member: |
+    uint32_t magic;
+- brief: |
+    This member contains a number which is sent as next message.
+  description: null
+  member: |
+    uint8_t send_msg_counter
+- brief: |
+    This member contains a buffer to receive messages from the queue.
+  description: null
+  member: |
+    uint8_t receive_buffer[ MAXIMUM_MESSAGE_SIZE ]
+- brief: |
+    This member contains a buffer to receive the messages size.
+  description: null
+  member: |
+    size_t receive_size
+- brief: |
+    This member specifies the ${../if/receive:/params[0]/name} parameter
+    for the action.
+  description: null
+  member: |
+    rtems_id id_param
+- brief: |
+    This member specifies the ${../if/receive:/params[1]/name} parameter
+    for the action.
+  description: null
+  member: |
+    void *buffer_param
+- brief: |
+    This member specifies the ${../if/receive:/params[2]/name} parameter
+    for the action.
+  description: null
+  member: |
+    size_t *size_param
+- brief: |
+    This member specifies the ${../if/receive:/params[3]/name} parameter
+    for the action.
+  description: null
+  member: |
+    rtems_option option_set_param
+- brief: |
+    This member specifies the ${../if/receive:/params[4]/name} parameter
+    for the action.
+  description: null
+  member: |
+    rtems_interval timeout_param
+- brief: |
+    This member contains the returned ${/glossary/statuscode:/term}
+    of the action.
+  description: null
+  member: |
+    rtems_status_code status
+- brief: |
+    This member contains the duration of the action in ticks.
+  description: null
+  member: |
+    uint32_t action_duration
+- brief: |
+    This member contains the ${/glossary/task:/term} identifier of the
+    main ${/glossary/task:/term}.
+  description: null
+  member: |
+    rtems_id task_id
+- brief: |
+    This member contains the ${/glossary/task:/term} identifier of the
+    worker ${/glossary/task:/term}.
+  description: null
+  member: |
+    rtems_id worker_id
+- brief: |
+    This member contains a pointer to a function which is executed while
+    the worker is waiting to receive a message (`delete(), nop()``).
+  description: null
+  member: |
+    void (*concurrent_activity)( void *ctx_in )
+- brief: |
+    This member contains a pointer to a function which is executed
+    to check that the action has not changed the content of the
+    ${/glossary/messagequeue:/term}.
+  description: null
+  member: |
+    void (*check_msgq_unchanged)( void *ctx_in )
+test-context-support: |
+  #define MAXIMUM_PENDING_MESSAGES 3
+  #define MAXIMUM_MESSAGE_SIZE 5
+test-description: null
+test-header: null
+test-includes:
+- rtems.h
+- rtems/score/statesimpl.h
+test-local-includes:
+- tx-support.h
+- tx-thread-queue.h
+- tr-tq-enqueue-fifo.h
+- tr-tq-enqueue-priority.h
+test-prepare: |
+  rtems_status_code status;
+  rtems_event_set   event_set;
+
+  /* Clean away pending events - happens after RTEMS_WAIT + RTEMS_NO_TIMEOUT */
+  status = rtems_event_receive(
+    RTEMS_ALL_EVENTS,
+    RTEMS_NO_WAIT | RTEMS_EVENT_ANY,
+    RTEMS_NO_TIMEOUT,
+    &event_set
+  );
+  T_true( status == RTEMS_SUCCESSFUL || status == RTEMS_UNSATISFIED );
+
+  ctx->send_msg_counter = 0;
+  ctx->receive_size     = SIZE_MAX;
+  memset( ctx->receive_buffer, UINT8_MAX, MAXIMUM_MESSAGE_SIZE );
+test-setup:
+  brief: null
+  code: |
+    rtems_status_code status;
+
+    memset( ctx, 0, sizeof( *ctx ) );
+    ctx->magic                  = magic;
+    ctx->tq_ctx.enqueue         = ReceiveMsg;
+    ctx->tq_ctx.surrender       = TQDoNothing;
+    ctx->tq_ctx.convert_status  = TQConvertStatusClassic;
+    ctx->tq_ctx.enqueue_prepare = EnqueuePrepare;
+    ctx->tq_ctx.enqueue_done    = EnqueueDone;
+    TQInitialize( &ctx->tq_ctx );
+
+    /*
+     * ctx->tq_ctx.thread_queue_id = RTEMS_ID_NONE indicates that the message
+     * queue does currently not exist. A message queue is created
+     * two times in a row in a single test cycle. First after the attributes
+     * are set in the preconditions. That queue is used for all tests of
+     * usual message queue requirements. Second a message queue is recreated
+     * in the tasks post-conditions for the tests of the task queue.
+     * To avoid an accidentally creation of a second
+     * message queue without the first being deleted prior,
+     * ctx->tq_ctx.thread_queue_id is checked for being RTEMS_ID_NONE before
+     * any message queue is created - a run-time sanity check.
+     */
+    ctx->tq_ctx.thread_queue_id = RTEMS_ID_NONE;
+    ctx->task_id                = rtems_task_self();
+
+    /* Note: TQInitialize() will assign the "main" task priority PRIO_NORMAL */
+    status = rtems_task_create(
+      rtems_build_name( 'W', 'O', 'R', 'K' ),
+      PRIO_HIGH,
+      RTEMS_MINIMUM_STACK_SIZE,
+      RTEMS_DEFAULT_MODES,
+      RTEMS_DEFAULT_ATTRIBUTES,
+      &ctx->worker_id
+    );
+    T_rsc_success( status );
+
+    status = rtems_task_start(
+      ctx->worker_id,
+      WorkerTask,
+      (rtems_task_argument) NULL
+    );
+    T_rsc_success( status );
+  description: null
+test-stop: null
+test-support: |
+  typedef ${.:/test-context-type} Context;
+  static const uint32_t        magic = 0xA55CA3D1; /* an arbitrary number */
+  static const rtems_interval  timeout_ticks = 3;
+  static const rtems_event_set wake_main_task_event = RTEMS_EVENT_17;
+
+  static void DoAction( void *ctx_in )
+  {
+    Context *ctx = ctx_in;
+    ctx->status = rtems_message_queue_receive(
+      ctx->id_param,
+      ctx->buffer_param,
+      ctx->size_param,
+      ctx->option_set_param,
+      ctx->timeout_param
+    );
+  }
+
+  static void WorkerTask( unsigned int argument )
+  {
+    Context *ctx = (Context *) argument;
+    if ( ctx != NULL ) {
+      T_assert_eq_u32( ctx->magic, magic ); /* Run-time type check */
+      DoAction( ctx );
+      T_rsc_success( rtems_event_send( ctx->task_id, wake_main_task_event ) );
+    }
+    T_rsc_success( rtems_task_suspend( RTEMS_SELF ) );
+  }
+
+  static void WorkerDoAction( void *ctx_in )
+  {
+    rtems_status_code status;
+    Context *ctx = ctx_in;
+    T_assert_eq_u32( ctx->magic, magic ); /* Run-time type check */
+    status = rtems_task_restart( ctx->worker_id, (rtems_task_argument) ctx );
+    T_rsc_success( status );
+  }
+
+  static uint32_t WaitForWorker( Context *ctx )
+  {
+    uint32_t ticks_to_wait = timeout_ticks + 1;
+    rtems_status_code status;
+    rtems_event_set event_set;
+
+     for ( ; ticks_to_wait > 0; --ticks_to_wait ) {
+      /* Check whether the worker finished executing the action */
+      status = rtems_event_receive(
+        RTEMS_PENDING_EVENTS,
+        RTEMS_NO_WAIT | RTEMS_EVENT_ANY,
+        RTEMS_NO_TIMEOUT,
+        &event_set
+      );
+      T_rsc_success( status );
+
+      if ( ( event_set & wake_main_task_event ) == wake_main_task_event ) {
+        break;
+      }
+      TimecounterTick();
+    }
+
+    if ( ctx->timeout_param != RTEMS_NO_TIMEOUT ) {
+      /* Wait till the worker task finishes */
+      status = rtems_event_receive(
+        wake_main_task_event,
+        RTEMS_DEFAULT_OPTIONS,
+        RTEMS_NO_TIMEOUT,
+        &event_set
+      );
+    T_rsc_success( status );
+    }
+
+    return timeout_ticks + 1 - ticks_to_wait;
+  }
+
+  static void MessageQueueSetup( Context *ctx )
+  {
+    rtems_status_code status;
+    /* Sanity check: Make sure the message queue does not exist, yet. */
+    T_assert_eq_u32( ctx->tq_ctx.thread_queue_id, RTEMS_ID_NONE );
+    rtems_message_queue_config config = {
+      .name = rtems_build_name( 'M', 'S', 'G', 'Q' ),
+      .maximum_pending_messages = MAXIMUM_PENDING_MESSAGES,
+      .maximum_message_size = MAXIMUM_MESSAGE_SIZE,
+      .storage_area = ctx->storage_area,
+      .storage_size = sizeof( ctx->storage_area ),
+      .storage_free = NULL,
+      .attributes = ctx->attribute_set
+    };
+
+    status = rtems_message_queue_construct(
+      &config,
+      &ctx->tq_ctx.thread_queue_id
+    );
+    T_rsc_success( status );
+
+    if ( ctx->id_param != RTEMS_ID_NONE ) {
+      ctx->id_param = ctx->tq_ctx.thread_queue_id;
+    }
+  }
+
+  static void MessageQueueTeardown( Context *ctx )
+  {
+    rtems_status_code status;
+    if ( ctx->tq_ctx.thread_queue_id != RTEMS_ID_NONE ) {
+      status = rtems_message_queue_delete( ctx->tq_ctx.thread_queue_id );
+      T_rsc_success( status );
+      ctx->tq_ctx.thread_queue_id = RTEMS_ID_NONE;
+    }
+  }
+
+  static void CheckForNoMessage(
+    rtems_status_code status,
+    uint8_t *message_buffer,
+    size_t message_size
+  )
+  {
+    T_rsc( status, RTEMS_UNSATISFIED  );
+  }
+
+  static void CheckForFirstMessage(
+    rtems_status_code status,
+    uint8_t *message_buffer,
+    size_t message_size
+  )
+  {
+    T_rsc_success( status );
+    T_eq_u32( message_size, 1 );
+    T_eq_u8( message_buffer[0], 0 );
+  }
+
+  static void CheckForSecondMessage(
+    rtems_status_code status,
+    uint8_t *message_buffer,
+    size_t message_size
+  )
+  {
+    T_rsc_success( status );
+    T_eq_u32( message_size, 3 );
+    T_eq_u8( message_buffer[0], 1 );
+    T_eq_u8( message_buffer[1], 1 );
+    T_eq_u8( message_buffer[2], 1 );
+  }
+
+  static void CheckForThirdMessage(
+    rtems_status_code status,
+    uint8_t *message_buffer,
+    size_t message_size
+  )
+  {
+    T_rsc_success( status );
+    T_eq_u32( message_size, 5 );
+    T_eq_u8( message_buffer[0], 2 );
+    T_eq_u8( message_buffer[1], 2 );
+    T_eq_u8( message_buffer[2], 2 );
+    T_eq_u8( message_buffer[3], 2 );
+    T_eq_u8( message_buffer[4], 2 );
+  }
+
+  static void PopMessage(
+    Context *ctx,
+    void (*check_fn)(
+      rtems_status_code status,
+      uint8_t *message_buffer,
+      size_t message_size
+    )
+  )
+  {
+    rtems_status_code status;
+    uint8_t message_buffer[ MAXIMUM_MESSAGE_SIZE ];
+    size_t message_size;
+
+    status = rtems_message_queue_receive(
+      ctx->tq_ctx.thread_queue_id,
+      &message_buffer,
+      &message_size,
+      RTEMS_LOCAL | RTEMS_NO_WAIT,
+      RTEMS_NO_TIMEOUT
+    );
+
+   check_fn( status, message_buffer, message_size );
+  }
+
+  static void CheckForNoMessageInQueue( void *ctx_in )
+  {
+    Context *ctx = ctx_in;
+    T_assert_eq_u32( ctx->magic, magic ); /* Run-time type check */
+    PopMessage( ctx, CheckForNoMessage );
+  }
+
+  static void CheckForOneMessageInQueue( void *ctx_in )
+  {
+    Context *ctx = ctx_in;
+    T_assert_eq_u32( ctx->magic, magic ); /* Run-time type check */
+    PopMessage( ctx, CheckForFirstMessage );
+    PopMessage( ctx, CheckForNoMessage );
+  }
+
+  static void CheckForSeveralMessagesInQueue( void *ctx_in )
+  {
+    Context *ctx = ctx_in;
+    T_assert_eq_u32( ctx->magic, magic ); /* Run-time type check */
+    PopMessage( ctx, CheckForFirstMessage );
+    PopMessage( ctx, CheckForSecondMessage );
+    PopMessage( ctx, CheckForThirdMessage );
+    PopMessage( ctx, CheckForNoMessage );
+  }
+
+  static void MessageQueueNop( void *ctx_in )
+  {
+    (void) ctx_in;
+  }
+
+  static void MessageQueueDelete( void *ctx_in )
+  {
+    Context *ctx = ctx_in;
+    T_assert_eq_u32( ctx->magic, magic ); /* Run-time type check */
+    MessageQueueTeardown( ctx );
+  }
+
+  static Context *ToContext( TQContext *tqctx )
+  {
+    Context *ctx = RTEMS_CONTAINER_OF( tqctx, Context, tq_ctx );
+    T_assert_eq_u32( ctx->magic, magic ); /* Run-time type check */
+    return ctx;
+  }
+
+  static Status_Control ReceiveMsg( TQContext *tqctx, TQWait wait )
+  {
+    Context *ctx = ToContext( tqctx );
+    rtems_status_code status;
+    rtems_option option_set;
+    rtems_interval timeout;
+
+    switch ( wait ) {
+      case TQ_WAIT_FOREVER:
+        option_set = RTEMS_WAIT;
+        timeout = RTEMS_NO_TIMEOUT;
+        break;
+      case TQ_WAIT_TICKS:
+        option_set = RTEMS_WAIT;
+        timeout = UINT32_MAX;
+        break;
+      default:
+        option_set = RTEMS_NO_WAIT;
+        timeout = 0;
+        break;
+    }
+
+    status = rtems_message_queue_receive(
+      ctx->tq_ctx.thread_queue_id,
+      ctx->receive_buffer,
+      &ctx->receive_size,
+      option_set,
+      timeout
+    );
+
+    return STATUS_BUILD( status, 0 );
+  }
+
+  static void SendMsg( TQContext *tqctx )
+  {
+    Context *ctx = ToContext( tqctx );
+    rtems_status_code status;
+    uint8_t msg[ MAXIMUM_MESSAGE_SIZE ];
+
+    memset( msg, ctx->send_msg_counter, MAXIMUM_MESSAGE_SIZE );
+    status = rtems_message_queue_send(
+      ctx->tq_ctx.thread_queue_id,
+      msg,
+      ( ctx->send_msg_counter * 2 ) % MAXIMUM_MESSAGE_SIZE + 1
+    );
+    T_rsc_success( status );
+    ++ctx->send_msg_counter;
+  }
+
+  static void EnqueuePrepare( TQContext *tqctx )
+  {
+    Status_Control status;
+
+    /* Check that the message queue is empty */
+    status = TQEnqueue( tqctx, TQ_NO_WAIT );
+    T_eq_int( status, STATUS_BUILD( RTEMS_UNSATISFIED, 0 ) );
+  }
+
+  static void EnqueueDone( TQContext *tqctx )
+  {
+    uint32_t i;
+
+    for ( i = 0; i < tqctx->how_many; ++i ) {
+      SendMsg( tqctx );
+    }
+  }
+test-target: testsuites/validation/tc-message-receive.c
+test-teardown:
+  brief: null
+  code: |
+    T_rsc_success( rtems_task_delete( ctx->worker_id ) );
+    TQDestroy( &ctx->tq_ctx );
+  description: null
+text: ${.:text-template}
+transition-map:
+
+# ---- Ok Case ----
+
+- enabled-by: true
+  post-conditions:
+    Status: Ok
+    Delay: None
+    Tasks: N/A
+    Size: First
+    Msg: First
+    MsgQueue:
+      - if:
+          pre-conditions:
+            MsgQueue: One
+        then: Empty
+      - else: OneLess
+    Tasks: N/A
+  pre-conditions:
+    Buffer:
+      - Valid
+    Size:
+      - Valid
+    Id:
+      - Valid
+    DuringWait:
+      - Nop
+    TaskQueue: all
+    Wait: all
+    MsgQueue:
+      - One
+      - Several
+    Storage: all
+
+# ---- Empty Queue ----
+
+- enabled-by: true
+  post-conditions:
+    Status:
+      - if:
+          pre-conditions:
+            Wait: Forever
+        then: N/A
+      - if:
+          pre-conditions:
+            Wait: 'No'
+        then: Unsat
+      - else: Timeout
+    Delay:
+      - if:
+          pre-conditions:
+            Wait: 'No'
+        then: None
+      - if:
+          pre-conditions:
+            Wait: Timeout
+        then: Ticks
+      - else: Forever
+    Size: Nop
+    Msg: Nop
+    MsgQueue: Nop
+
+    Tasks:
+      - if:
+          pre-conditions:
+            Wait: 'No'
+        then: N/A
+      - if:
+          pre-conditions:
+            TaskQueue: Fifo
+        then: Fifo
+      - else: Priority
+  pre-conditions:
+    Buffer:
+      - Valid
+    Size:
+      - Valid
+    Id:
+      - Valid
+    DuringWait:
+      - Nop
+    TaskQueue: all
+    Wait: all
+    MsgQueue:
+      - Empty
+    Storage: all
+
+# ---- InvAddr: Buffer ----
+
+- enabled-by: true
+  post-conditions:
+    Status: InvAddr
+    Delay: None
+    Size: Nop
+    Msg: Nop
+    MsgQueue:
+      - if:
+          pre-conditions:
+            DuringWait: Deleted
+        then: N/A
+      - else: Nop
+    Tasks: N/A
+  pre-conditions:
+    Buffer:
+      - 'Null'
+    Size: all
+    Id: all
+    DuringWait: all
+    TaskQueue: all
+    Wait: all
+    MsgQueue: all
+    Storage: all
+
+# ---- InvAddr: Size ----
+
+- enabled-by: true
+  post-conditions:
+    Status: InvAddr
+    Delay: None
+    Size: Nop
+    Msg: Nop
+    MsgQueue:
+      - if:
+          pre-conditions:
+            DuringWait: Deleted
+        then: N/A
+      - else: Nop
+    Tasks: N/A
+  pre-conditions:
+    Buffer:
+      - Valid
+    Size:
+      - 'Null'
+    Id: all
+    DuringWait: all
+    TaskQueue: all
+    Wait: all
+    MsgQueue: all
+    Storage: all
+
+# ---- InvId ----
+
+- enabled-by: true
+  post-conditions:
+    Status: InvId
+    Delay: None
+    Size: Nop
+    Msg: Nop
+    MsgQueue:
+      - if:
+          pre-conditions:
+            DuringWait: Deleted
+        then: N/A
+      - else: Nop
+    Tasks: N/A
+  pre-conditions:
+    Buffer:
+      - Valid
+    Size:
+      - Valid
+    Id:
+      - Invalid
+    DuringWait: all
+    TaskQueue: all
+    Wait: all
+    MsgQueue: all
+    Storage: all
+
+# ---- Deleted ----
+
+- enabled-by: true
+  post-conditions:
+    Status: Deleted
+    Delay: None
+    Size: Nop
+    Msg: Nop
+    MsgQueue: N/A
+    Tasks: N/A
+  pre-conditions:
+    Buffer:
+      - Valid
+    Size:
+      - Valid
+    Id:
+      - Valid
+    DuringWait:
+      - Deleted
+    TaskQueue: all
+    Wait: all
+    MsgQueue: all
+    Storage: all
+
+# ---- Impossible Deleted Cases ----
+
+- enabled-by: true
+  post-conditions: NoWait
+  pre-conditions:
+    Buffer:
+      - Valid
+    Size:
+      - Valid
+    Id:
+      - Valid
+    DuringWait:
+      - Deleted
+    TaskQueue: all
+    Wait:
+      - 'No'
+    MsgQueue: all
+    Storage: all
+
+- enabled-by: true
+  post-conditions: NoWait
+  pre-conditions:
+    Buffer:
+      - Valid
+    Size:
+      - Valid
+    Id:
+      - Valid
+    DuringWait:
+      - Deleted
+    TaskQueue: all
+    Wait:
+      - Timeout
+      - Forever
+    MsgQueue:
+      - One
+      - Several
+    Storage: all
+type: requirement
diff --git a/spec/rtems/message/req/urgent-send.yml b/spec/rtems/message/req/urgent-send.yml
new file mode 100644
index 0000000..92c1cbe
--- /dev/null
+++ b/spec/rtems/message/req/urgent-send.yml
@@ -0,0 +1,758 @@
+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: interface-function
+  uid: ../if/send
+- role: interface-function
+  uid: ../if/urgent
+post-conditions:
+- name: Status
+  states:
+  - name: Ok
+    test-code: |
+      T_rsc_success( ctx->status );
+    text: |
+      The return status of the called directive (${../if/send:/name} or
+      ${../if/urgent:/name}) shall be ${../../status/if/successful:/name}
+  - name: InvId
+    test-code: |
+      T_rsc( ctx->status, RTEMS_INVALID_ID );
+    text: |
+      The return status of the called directive (${../if/send:/name} or
+      ${../if/urgent:/name}) shall be ${../../status/if/invalid-id:/name}.
+  - name: InvAddr
+    test-code: |
+      T_rsc( ctx->status, RTEMS_INVALID_ADDRESS );
+    text: |
+      The return status of the called directive (${../if/send:/name} or
+      ${../if/urgent:/name}) shall be ${../../status/if/invalid-address:/name}.
+  - name: InvSize
+    test-code: |
+      T_rsc( ctx->status, RTEMS_INVALID_SIZE );
+    text: |
+      The return status of the called directive (${../if/send:/name} or
+      ${../if/urgent:/name}) shall be ${../../status/if/invalid-size:/name}.
+  - name: TooMany
+    test-code: |
+      T_rsc( ctx->status, RTEMS_TOO_MANY );
+    text: |
+      The return status of the called directive (${../if/send:/name} or
+      ${../if/urgent:/name}) shall be ${../../status/if/too-many:/name}.
+  test-epilogue: null
+  test-prologue: null
+- name: MsgQueue
+  states:
+  - name: Empty
+    test-code: |
+      PopMessage( ctx, CheckForNoMessage );
+    text: |
+      The ${/glossary/messagequeue:/term} shall be empty after the
+      return of the ${../if/send:/name} or ${../if/urgent:/name} call.
+  - name: One
+    test-code: |
+      PopMessage( ctx, CheckForSendMessage );
+      PopMessage( ctx, CheckForNoMessage );
+    text: |
+      The ${/glossary/messagequeue:/term} shall contain only the send message
+      after the return of the ${../if/send:/name} or
+      ${../if/urgent:/name} call.
+  - name: Prepend
+    test-code: |
+      PopMessage( ctx, CheckForSendMessage );
+      ctx->check_msgq_unchanged( ctx );
+      PopMessage( ctx, CheckForNoMessage );
+    text: |
+      The ${/glossary/messagequeue:/term} shall contain the message
+      send by the last call to ${../if/urgent:/name} as
+      ${../glossary/firstmessage:/term} followed by all the messages
+      which were in the ${/glossary/messagequeue:/term} before that call
+      (in the same order and each message with the same content and size).
+  - name: Append
+    test-code: |
+      ctx->check_msgq_unchanged( ctx );
+      PopMessage( ctx, CheckForSendMessage );
+      PopMessage( ctx, CheckForNoMessage );
+    text: |
+      The ${/glossary/messagequeue:/term} shall contain the message
+      send by the last call to ${../if/send:/name} as
+      ${../glossary/lastmessage:/term} preceded by all the messages
+      which were in the ${/glossary/messagequeue:/term} before that call
+      (in the same order and each message with the same content and size).
+  - name: Nop
+    test-code: |
+      ctx->check_msgq_unchanged( ctx );
+      PopMessage( ctx, CheckForNoMessage );
+    text: |
+      Objects referenced by the ${../if/send:/params[0]/name}
+      parameter in past call to ${../if/send:/name} or
+      ${../if/urgent:/name} shall not be accessed by that
+      call (see also ${../glossary/nop:/term}).
+  test-epilogue: null
+  test-prologue: null
+- name: Receiver
+  states:
+  - name: GotMsg
+    test-code: |
+      CheckForSendMessage(
+        ctx,
+        ctx->receive_status,
+        ctx->receive_buffer,
+        ctx->receive_size
+      );
+    text: |
+      The ${../glossary/receiver:/term} shall receive the message
+      send by the last call to the ${../if/send:/name} or
+      ${../if/urgent:/name} directive.
+  - name: Waiting
+    test-code: |
+      T_rsc( ctx->receive_status, RTEMS_TIMEOUT );
+    text: |
+      The ${../glossary/receiver:/term} shall still wait to receive
+      a message after the last call to the ${../if/send:/name} or
+      ${../if/urgent:/name} directive.
+  test-epilogue: null
+  test-prologue: null
+pre-conditions:
+- name: Buffer
+  states:
+  - name: Valid
+    test-code: |
+      uint8_t i;
+      for ( i = 0; i < MAXIMUM_MESSAGE_SIZE; ++i ) {
+        ctx->send_message[i] = 42 + i;
+      }
+      ctx->buffer_param = &ctx->send_message;
+    text: |
+      While the ${../if/send:/params[1]/name} parameter references a memory
+      area where the message to be sent is stored.
+  - name: 'Null'
+    test-code: |
+      ctx->buffer_param = NULL;
+    text: |
+      While the ${../if/send:/params[1]/name} parameter is ${/c/if/null:/name}.
+  test-epilogue: null
+  test-prologue: null
+- name: Id
+  states:
+  - name: Valid
+    test-code: |
+      ctx->id_param = ctx->message_queue_id;
+    text: |
+      While the ${../if/send:/params[0]/name} parameter is valid.
+  - name: Invalid
+    test-code: |
+      ctx->id_param = RTEMS_ID_NONE;
+    text: |
+      While the ${../if/send:/params[0]/name} parameter is invalid.
+  test-epilogue: null
+  test-prologue: null
+- name: Size
+  states:
+  - name: Zero
+    test-code: |
+      ctx->size_param = 0;
+    text: |
+      While the ${../if/send:/params[2]/name} parameter is 0.
+  - name: SomeSize
+    test-code: |
+      ctx->size_param = MAXIMUM_MESSAGE_SIZE / 2 + 1;
+    text: |
+      While the ${../if/send:/params[2]/name} parameter has a value
+      between 0 and the ${../glossary/maximummessagesize:/term}.
+  - name: MaxSize
+    test-code: |
+      ctx->size_param = MAXIMUM_MESSAGE_SIZE;
+    text: |
+      While the ${../if/send:/params[2]/name} parameter has a value
+      of the ${../glossary/maximummessagesize:/term}.
+  - name: TooLarge
+    test-code: |
+      ctx->size_param = MAXIMUM_MESSAGE_SIZE + 1;
+    text: |
+      While the ${../if/send:/params[2]/name} parameter has a value
+      greater than the ${../glossary/maximummessagesize:/term}.
+  test-epilogue: null
+  test-prologue: null
+- name: MsgQueue
+  states:
+  - name: Empty
+    test-code: |
+      /* Message queue is already empty. */
+      ctx->check_msgq_unchanged = CheckForNoMessageInQueue;
+    text: |
+      While there is no message in the ${/glossary/messagequeue:/term}.
+  - name: One
+    test-code: |
+      SendMsg( ctx );
+      ctx->check_msgq_unchanged = CheckForOneMessageInQueue;
+    text: |
+      While there is exactly one message in the ${/glossary/messagequeue:/term}.
+  - name: Several
+    test-code: |
+      SendMsg( ctx );
+      SendMsg( ctx );
+      ctx->check_msgq_unchanged = CheckForSeveralMessagesInQueue;
+    text: |
+      While there are more than one and less than
+      ${../glossary/maximumpendingmessages:/term} in the
+      ${/glossary/messagequeue:/term}.
+  - name: Full
+    test-code: |
+      SendMsg( ctx );
+      SendMsg( ctx );
+      SendMsg( ctx );
+      ctx->check_msgq_unchanged = CheckForAllMessagesInQueue;
+    text: |
+      While there are ${../glossary/maximumpendingmessages:/term} in the
+      ${/glossary/messagequeue:/term}.
+  test-epilogue: null
+  test-prologue: null
+- name: Receiver
+  states:
+  - name: Waiting
+    test-code: |
+      ctx->is_receiver_waiting = true;
+    text: |
+      While a ${../glossary/receiver:/term} is waiting to receive a message.
+  - name: 'No'
+    test-code: |
+      ctx->is_receiver_waiting = false;
+    text: |
+      While no ${../glossary/receiver:/term} is waiting to receive a message.
+  test-epilogue: null
+  test-prologue: null
+- name: Directive
+  states:
+  - name: Send
+    test-code: |
+      ctx->action = rtems_message_queue_send;
+    text: |
+      While the directive ${../if/send:/name} is called.
+  - name: Urgent
+    test-code: |
+      ctx->action = rtems_message_queue_urgent;
+    text: |
+      While the directive ${../if/urgent:/name} is called.
+  test-epilogue: null
+  test-prologue: null
+- name: Storage
+  states:
+  - name: Nop
+    test-code: |
+      /* Only a requirement text. */
+    text: |
+      While the memory area to which a pointer is provided as member
+      ${../if/config:/definition[3]/default/name} of type
+      ${../if/config:/name} when the ${/glossary/messagequeue:/term} is
+      constructed by ${../if/construct:/name} is altered only by the
+      ${/glossary/rtems:/term} operating system.
+  test-epilogue: null
+  test-prologue: null
+rationale: null
+references: []
+requirement-type: functional
+skip-reasons:
+  NoWait: |
+    The ${/glossary/messagequeue:/term} must be empty for an
+    ${../glossary/receiver:/term} to wait for a message.
+test-action: |
+  if ( ctx->is_receiver_waiting ) {
+    SendEvents( ctx->worker_id, EVENT_RECEIVE );
+  }
+
+  ctx->status = (ctx->action)(
+    ctx->id_param,
+    ctx->buffer_param,
+    ctx->size_param
+  );
+
+  if ( ctx->is_receiver_waiting ) {
+    FinalClockTick();
+  }
+test-brief: null
+test-cleanup: |
+    T_rsc_success( rtems_message_queue_delete( ctx->message_queue_id ) );
+test-context:
+- brief: |
+    This member contains a valid ${/glossary/id:/term} of a
+    ${/glossary/messagequeue:/term}.
+  description: null
+  member: |
+    rtems_id message_queue_id
+- brief: |
+    This member is used as storage area for the
+    ${/glossary/messagequeue:/term}.
+  description: null
+  member: |
+    RTEMS_MESSAGE_QUEUE_BUFFER( MAXIMUM_MESSAGE_SIZE )
+      storage_area[ MAXIMUM_PENDING_MESSAGES]
+- brief: |
+    This member contains always the same arbitrary number ``magic``.
+  description: |
+    It is used for run-time type checking.
+  member: |
+    uint32_t magic;
+- brief: |
+    This member contains a number which is sent as next message.
+  description: null
+  member: |
+    uint8_t send_msg_counter
+- brief: |
+    This member contains a buffer to receive messages from the queue.
+  description: null
+  member: |
+    uint8_t receive_buffer[ MAXIMUM_MESSAGE_SIZE ]
+- brief: |
+    This member contains a buffer to receive the messages size.
+  description: null
+  member: |
+    size_t receive_size
+- brief: |
+    This member contains the returned ${/glossary/statuscode:/term}
+    of the receiver.
+  description: null
+  member: |
+    rtems_status_code receive_status
+- brief: |
+    This member indicates whether the a receiver task should be started
+    to receive a message.
+  description: null
+  member: |
+    bool is_receiver_waiting
+- brief: |
+    This member contains the message to be sent by the action.
+  description: null
+  member: |
+    uint8_t send_message[ MAXIMUM_MESSAGE_SIZE ]
+- brief: |
+    This member specifies the directive to be called as action.
+  description: This is either ${../if/send:/name} or ${../if/urgent:/name}.
+  member:
+     rtems_status_code (*action)( rtems_id id, const void *buffer, size_t size )
+- brief: |
+    This member specifies the ${../if/send:/params[0]/name} parameter
+    for the action.
+  description: null
+  member: |
+    rtems_id id_param
+- brief: |
+    This member specifies the ${../if/send:/params[1]/name} parameter
+    for the action.
+  description: null
+  member: |
+    void *buffer_param
+- brief: |
+    This member specifies the ${../if/send:/params[2]/name} parameter
+    for the action.
+  description: null
+  member: |
+    size_t size_param
+- brief: |
+    This member contains the returned ${/glossary/statuscode:/term}
+    of the action.
+  description: null
+  member: |
+    rtems_status_code status
+- brief: |
+    This member contains the ${/glossary/task:/term} identifier of the
+    main ${/glossary/task:/term}.
+  description: null
+  member: |
+    rtems_id task_id
+- brief: |
+    This member contains the ${/glossary/task:/term} identifier of the
+    worker ${/glossary/task:/term}.
+  description: null
+  member: |
+    rtems_id worker_id
+- brief: |
+    This member contains a pointer to a function which is executed
+    to check that the action has not changed the content of the
+    ${/glossary/messagequeue:/term}.
+  description: null
+  member: |
+    void (*check_msgq_unchanged)( void *ctx_in )
+test-context-support: |
+  #define MAXIMUM_PENDING_MESSAGES 3
+  #define MAXIMUM_MESSAGE_SIZE 5
+test-description: null
+test-header: null
+test-includes:
+- rtems.h
+test-local-includes:
+- tx-support.h
+test-prepare: |
+  rtems_status_code status;
+
+  ctx->send_msg_counter = 0;
+
+  rtems_message_queue_config config = {
+    .name                     = rtems_build_name( 'M', 'S', 'G', 'Q' ),
+    .maximum_pending_messages = MAXIMUM_PENDING_MESSAGES,
+    .maximum_message_size     = MAXIMUM_MESSAGE_SIZE,
+    .storage_area             = ctx->storage_area,
+    .storage_size             = sizeof( ctx->storage_area ),
+    .storage_free             = NULL,
+    .attributes               = RTEMS_DEFAULT_ATTRIBUTES
+  };
+
+  status = rtems_message_queue_construct(
+    &config,
+    &ctx->message_queue_id
+  );
+  T_rsc_success( status );
+test-setup:
+  brief: null
+  code: |
+    ctx->magic   = MAGIC;
+    ctx->task_id = rtems_task_self();
+
+    SetSelfPriority( PRIO_NORMAL );
+    ctx->worker_id = CreateTask( "WORK", PRIO_HIGH );
+    StartTask( ctx->worker_id, WorkerTask, ctx );
+  description: null
+test-stop: null
+test-support: |
+  typedef ${.:/test-context-type} Context;
+  static const uint32_t MAGIC = 0xA66FE31; /* an arbitrary number */
+  static const rtems_interval TIMEOUT_TICKS = 1;
+  static const rtems_event_set EVENT_RECEIVE = RTEMS_EVENT_17;
+
+  static void Receive( Context *ctx )
+  {
+    ctx->receive_status = rtems_message_queue_receive(
+      ctx->message_queue_id,
+      ctx->receive_buffer,
+      &ctx->receive_size,
+      RTEMS_WAIT,
+      TIMEOUT_TICKS
+    );
+  }
+
+  static void WorkerTask( rtems_task_argument argument )
+  {
+    Context *ctx = (Context *) argument;
+
+    while ( true ) {
+      rtems_event_set events;
+
+      events = ReceiveAnyEvents();
+
+      if ( ( events & EVENT_RECEIVE ) != 0 ) {
+        Receive( ctx );
+      }
+    }
+  }
+
+  static void CheckForNoMessage(
+    Context *ctx,
+    rtems_status_code status,
+    uint8_t *message_buffer,
+    size_t message_size
+  )
+  {
+    (void) ctx;
+    T_rsc( status, RTEMS_UNSATISFIED  );
+  }
+
+  static void CheckForFirstMessage(
+    Context *ctx,
+    rtems_status_code status,
+    uint8_t *message_buffer,
+    size_t message_size
+  )
+  {
+    (void) ctx;
+    T_rsc_success( status );
+    T_eq_u32( message_size, 1 );
+    T_eq_u8( message_buffer[0], 0 );
+  }
+
+  static void CheckForSecondMessage(
+    Context *ctx,
+    rtems_status_code status,
+    uint8_t *message_buffer,
+    size_t message_size
+  )
+  {
+    (void) ctx;
+    T_rsc_success( status );
+    T_eq_u32( message_size, 3 );
+    T_eq_u8( message_buffer[0], 1 );
+    T_eq_u8( message_buffer[1], 1 );
+    T_eq_u8( message_buffer[2], 1 );
+  }
+
+  static void CheckForThirdMessage(
+    Context *ctx,
+    rtems_status_code status,
+    uint8_t *message_buffer,
+    size_t message_size
+  )
+  {
+    (void) ctx;
+    T_rsc_success( status );
+    T_eq_u32( message_size, 5 );
+    T_eq_u8( message_buffer[0], 2 );
+    T_eq_u8( message_buffer[1], 2 );
+    T_eq_u8( message_buffer[2], 2 );
+    T_eq_u8( message_buffer[3], 2 );
+    T_eq_u8( message_buffer[4], 2 );
+  }
+
+  static void CheckForSendMessage(
+    Context *ctx,
+    rtems_status_code status,
+    uint8_t *message_buffer,
+    size_t message_size
+  )
+  {
+    size_t i;
+    T_rsc_success( status );
+    T_eq_u32( message_size, ctx->size_param );
+    for ( i = 0; i < ctx->size_param; ++i ) {
+      T_eq_u8( message_buffer[i], ctx->send_message[i] );
+    }
+  }
+
+  static void PopMessage(
+    Context *ctx,
+    void (*check_fn)(
+      Context *ctx,
+      rtems_status_code status,
+      uint8_t *message_buffer,
+      size_t message_size
+    )
+  )
+  {
+    rtems_status_code status;
+    uint8_t message_buffer[ MAXIMUM_MESSAGE_SIZE ];
+    size_t message_size;
+
+    status = rtems_message_queue_receive(
+      ctx->message_queue_id,
+      &message_buffer,
+      &message_size,
+      RTEMS_LOCAL | RTEMS_NO_WAIT,
+      RTEMS_NO_TIMEOUT
+    );
+
+   check_fn( ctx, status, message_buffer, message_size );
+  }
+
+  static void CheckForNoMessageInQueue( void *ctx_in )
+  {}
+
+  static void CheckForOneMessageInQueue( void *ctx_in )
+  {
+    Context *ctx = ctx_in;
+    T_assert_eq_u32( ctx->magic, MAGIC ); /* Run-time type check */
+    PopMessage( ctx, CheckForFirstMessage );
+  }
+
+  static void CheckForSeveralMessagesInQueue( void *ctx_in )
+  {
+    Context *ctx = ctx_in;
+    T_assert_eq_u32( ctx->magic, MAGIC ); /* Run-time type check */
+    PopMessage( ctx, CheckForFirstMessage );
+    PopMessage( ctx, CheckForSecondMessage );
+  }
+
+  static void CheckForAllMessagesInQueue( void *ctx_in )
+  {
+    Context *ctx = ctx_in;
+    T_assert_eq_u32( ctx->magic, MAGIC ); /* Run-time type check */
+    PopMessage( ctx, CheckForFirstMessage );
+    PopMessage( ctx, CheckForSecondMessage );
+    PopMessage( ctx, CheckForThirdMessage );
+  }
+
+  static void SendMsg( Context *ctx )
+  {
+    rtems_status_code status;
+    uint8_t msg[ MAXIMUM_MESSAGE_SIZE ];
+
+    memset( msg, ctx->send_msg_counter, MAXIMUM_MESSAGE_SIZE );
+    status = rtems_message_queue_send(
+      ctx->message_queue_id,
+      msg,
+      ( ctx->send_msg_counter * 2 ) % MAXIMUM_MESSAGE_SIZE + 1
+    );
+    T_rsc_success( status );
+    ++ctx->send_msg_counter;
+  }
+
+test-target: testsuites/validation/tc-message-urgent-send.c
+test-teardown:
+  brief: null
+  code: |
+    DeleteTask( ctx->worker_id );
+    RestoreRunnerPriority();
+  description: null
+text: ${.:text-template}
+transition-map:
+
+# ---- Ok Case ----
+
+- enabled-by: true
+  post-conditions:
+    Status: Ok
+    MsgQueue:
+      - if:
+          pre-conditions:
+            MsgQueue: Empty
+            Receiver: Waiting
+        then: Empty
+      - if:
+          pre-conditions:
+            MsgQueue: Empty
+            Receiver: 'No'
+        then: One
+      - if:
+          pre-conditions:
+            MsgQueue: One
+            Directive: Urgent
+        then: Prepend
+      - if:
+          pre-conditions:
+            MsgQueue: Several
+            Directive: Urgent
+        then: Prepend
+      - else: Append
+    Receiver:
+      - if:
+          pre-conditions:
+            MsgQueue: Empty
+            Receiver: Waiting
+        then: GotMsg
+      - else: N/A
+  pre-conditions:
+    Buffer:
+      - Valid
+    Id:
+      - Valid
+    Size:
+      - Zero
+      - SomeSize
+      - MaxSize
+    MsgQueue:
+      - Empty
+      - One
+      - Several
+    Receiver: all
+    Directive: all
+    Storage: all
+
+# ---- InvAddr: Buffer ----
+
+- enabled-by: true
+  post-conditions:
+    Status: InvAddr
+    MsgQueue: Nop
+    Receiver:
+      - if:
+          pre-conditions:
+            Receiver: Waiting
+        then: Waiting
+      - else: N/A
+  pre-conditions:
+    Buffer:
+      - 'Null'
+    Id: all
+    Size: all
+    MsgQueue: all
+    Receiver: all
+    Directive: all
+    Storage: all
+
+# ---- InvId ----
+
+- enabled-by: true
+  post-conditions:
+    Status: InvId
+    MsgQueue: Nop
+    Receiver:
+      - if:
+          pre-conditions:
+            Receiver: Waiting
+        then: Waiting
+      - else: N/A
+  pre-conditions:
+    Buffer:
+      - Valid
+    Id:
+      - Invalid
+    Size: all
+    MsgQueue: all
+    Receiver: all
+    Directive: all
+    Storage: all
+
+# ---- InvSize ----
+
+- enabled-by: true
+  post-conditions:
+    Status: InvSize
+    MsgQueue: Nop
+    Receiver:
+      - if:
+          pre-conditions:
+            Receiver: Waiting
+        then: Waiting
+      - else: N/A
+  pre-conditions:
+    Buffer:
+      - Valid
+    Id:
+      - Valid
+    Size:
+      - TooLarge
+    MsgQueue: all
+    Receiver: all
+    Directive: all
+    Storage: all
+
+# ---- TooMany: Queue Full ----
+
+- enabled-by: true
+  post-conditions:
+    Status: TooMany
+    MsgQueue: Nop
+    Receiver: N/A
+  pre-conditions:
+    Buffer:
+      - Valid
+    Id:
+      - Valid
+    Size:
+      - Zero
+      - SomeSize
+      - MaxSize
+    MsgQueue:
+      - Full
+    Receiver:
+      - 'No'
+    Directive: all
+    Storage: all
+
+# ---- Impossible Cases ----
+
+- enabled-by: true
+  post-conditions: NoWait
+  pre-conditions:
+    Buffer: all
+    Id: all
+    Size: all
+    MsgQueue:
+      - One
+      - Several
+      - Full
+    Receiver:
+      - Waiting
+    Directive: all
+    Storage: all
+
+type: requirement
diff --git a/spec/rtems/message/val/message-macros.yml b/spec/rtems/message/val/message-macros.yml
new file mode 100644
index 0000000..c4eab2b
--- /dev/null
+++ b/spec/rtems/message/val/message-macros.yml
@@ -0,0 +1,120 @@
+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: []
+test-actions:
+
+# ---- RTEMS_DEFAULT_ATTRIBUTES ----
+
+- action-brief: |
+    Check the value of the ${../../attr/if/default:/name}.
+  action-code: |
+    /* No action */
+  checks:
+  - brief: |
+      Check ${../../attr/if/default:/name} equals ``RTEMS_FIFO | RTEMS_LOCAL``.
+    code: |
+      T_step_eq_int(
+        ${step},
+        ${../../attr/if/default:/name},
+        RTEMS_FIFO | RTEMS_LOCAL
+      );
+    links:
+    - role: validation
+      uid: ../req/attributes
+  links: []
+
+# ---- RTEMS_DEFAULT_OPTIONS ----
+
+- action-brief: |
+    Check the value of the ${../../option/if/default:/name}.
+  action-code: |
+    /* No action */
+  checks:
+  - brief: |
+      Check ${../../option/if/default:/name} equals ``RTEMS_WAIT``.
+    code: |
+      T_step_eq_int( ${step}, ${../../option/if/default:/name}, RTEMS_WAIT );
+    links:
+    - role: validation
+      uid: ../req/options
+  links: []
+
+# ---- RTEMS_MESSAGE_QUEUE_BUFFER ----
+
+- action-brief: |
+    Check the ${../if/buffer:/name} macro.
+  action-code: |
+    rtems_status_code     status;
+    rtems_id              id;
+
+    static const uint32_t maximum_pending_messages_0 = 1;
+    static const size_t   maximum_message_size_0 = 1;
+    RTEMS_MESSAGE_QUEUE_BUFFER( maximum_message_size_0 )
+                          storage_area_0[ maximum_pending_messages_0 ];
+    rtems_message_queue_config config_0 = {
+      .name = rtems_build_name( 'M', 'S', 'G', '0' ),
+      .maximum_pending_messages = maximum_pending_messages_0,
+      .maximum_message_size = maximum_message_size_0,
+      .storage_area = storage_area_0,
+      .storage_size = sizeof( storage_area_0 ),
+      .storage_free = NULL,
+      .attributes = ${../../option/if/default:/name}
+    };
+
+    static const uint32_t maximum_pending_messages_1 = 3;
+    static const size_t   maximum_message_size_1 = 5;
+    RTEMS_MESSAGE_QUEUE_BUFFER( maximum_message_size_1 )
+                          storage_area_1[ maximum_pending_messages_1 ];
+    rtems_message_queue_config config_1 = {
+      .name = rtems_build_name( 'M', 'S', 'G', '1' ),
+      .maximum_pending_messages = maximum_pending_messages_1,
+      .maximum_message_size = maximum_message_size_1,
+      .storage_area = storage_area_1,
+      .storage_size = sizeof( storage_area_1 ),
+      .storage_free = NULL,
+      .attributes = ${../../option/if/default:/name}
+    };
+  checks:
+  - brief: |
+      Check that the object defined by the ${../if/buffer:/name} expression
+      has the desired size.
+      ${../if/construct:/name} will return ${../../status/if/unsatisfied:/name}
+      instead of ${../../status/if/successful:/name} if the
+      object defined by the ${../if/buffer:/name} expression has incorrect
+      size.
+    code: |
+      status = rtems_message_queue_construct(
+        &config_0,
+        &id
+      );
+      T_step_rsc_success( ${step}, status );
+      T_step_rsc_success( ${step}, rtems_message_queue_delete( id ) );
+
+      status = rtems_message_queue_construct(
+        &config_1,
+        &id
+      );
+      T_step_rsc_success( ${step}, status );
+      T_step_rsc_success( ${step}, rtems_message_queue_delete( id ) );
+    links:
+    - role: validation
+      uid: ../req/buffer
+  links: []
+
+test-brief: |
+  Tests the macros of the ${../if/group:/name}.
+test-context: []
+test-context-support: null
+test-description: null
+test-header: null
+test-includes:
+- rtems.h
+test-local-includes: []
+test-setup: null
+test-stop: null
+test-support: null
+test-target: testsuites/validation/tc-message-macros.c
+test-teardown: null
+type: test-case



More information about the vc mailing list