summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrank Kühndel <frank.kuehndel@embedded-brains.de>2021-08-19 15:20:16 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2021-09-02 13:28:17 +0200
commit9f4f0ce9f9b57bb4422f845fd7507d5a01e8bde3 (patch)
treeb8a34a04a57b2afa557bb47c61ce8095733ad362
parentspec: Add LIFO to glossary (diff)
downloadrtems-central-9f4f0ce9f9b57bb4422f845fd7507d5a01e8bde3.tar.bz2
spec: Partially specify message manager
-rw-r--r--spec/rtems/message/glossary/firstmessage.yml36
-rw-r--r--spec/rtems/message/glossary/lastmessage.yml12
-rw-r--r--spec/rtems/message/glossary/maximummessagesize.yml16
-rw-r--r--spec/rtems/message/glossary/maximumpendingmessages.yml16
-rw-r--r--spec/rtems/message/glossary/nop.yml14
-rw-r--r--spec/rtems/message/glossary/receiver.yml17
-rw-r--r--spec/rtems/message/req/attributes.yml18
-rw-r--r--spec/rtems/message/req/buffer.yml28
-rw-r--r--spec/rtems/message/req/options.yml15
-rw-r--r--spec/rtems/message/req/receive.yml1061
-rw-r--r--spec/rtems/message/req/urgent-send.yml758
-rw-r--r--spec/rtems/message/val/message-macros.yml120
12 files changed, 2111 insertions, 0 deletions
diff --git a/spec/rtems/message/glossary/firstmessage.yml b/spec/rtems/message/glossary/firstmessage.yml
new file mode 100644
index 00000000..d206665f
--- /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 00000000..73642344
--- /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 00000000..9e0afb22
--- /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 00000000..c7702895
--- /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 00000000..372e356b
--- /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 00000000..f50fbec0
--- /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 00000000..5e9ecdff
--- /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 00000000..575434d7
--- /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 00000000..a0fe5a0b
--- /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 00000000..ce20d336
--- /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 00000000..92c1cbe0
--- /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 00000000..c4eab2bc
--- /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