diff options
author | Frank Kühndel <frank.kuehndel@embedded-brains.de> | 2021-08-19 15:20:16 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2021-09-02 13:28:17 +0200 |
commit | 9f4f0ce9f9b57bb4422f845fd7507d5a01e8bde3 (patch) | |
tree | b8a34a04a57b2afa557bb47c61ce8095733ad362 | |
parent | spec: Add LIFO to glossary (diff) | |
download | rtems-central-9f4f0ce9f9b57bb4422f845fd7507d5a01e8bde3.tar.bz2 |
spec: Partially specify message manager
-rw-r--r-- | spec/rtems/message/glossary/firstmessage.yml | 36 | ||||
-rw-r--r-- | spec/rtems/message/glossary/lastmessage.yml | 12 | ||||
-rw-r--r-- | spec/rtems/message/glossary/maximummessagesize.yml | 16 | ||||
-rw-r--r-- | spec/rtems/message/glossary/maximumpendingmessages.yml | 16 | ||||
-rw-r--r-- | spec/rtems/message/glossary/nop.yml | 14 | ||||
-rw-r--r-- | spec/rtems/message/glossary/receiver.yml | 17 | ||||
-rw-r--r-- | spec/rtems/message/req/attributes.yml | 18 | ||||
-rw-r--r-- | spec/rtems/message/req/buffer.yml | 28 | ||||
-rw-r--r-- | spec/rtems/message/req/options.yml | 15 | ||||
-rw-r--r-- | spec/rtems/message/req/receive.yml | 1061 | ||||
-rw-r--r-- | spec/rtems/message/req/urgent-send.yml | 758 | ||||
-rw-r--r-- | spec/rtems/message/val/message-macros.yml | 120 |
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 |