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/broadcast
post-conditions:
- name: Status
states:
- name: Ok
test-code: |
T_rsc_success( ctx->status );
text: |
The return status of ${../if/broadcast:/name} shall be
${../../status/if/successful:/name}
- name: InvId
test-code: |
T_rsc( ctx->status, RTEMS_INVALID_ID );
text: |
The return status of ${../if/broadcast:/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/broadcast:/name} shall be
${../../status/if/invalid-address:/name}.
- name: InvSize
test-code: |
T_rsc( ctx->status, RTEMS_INVALID_SIZE );
text: |
The return status of ${../if/broadcast:/name} shall be
${../../status/if/invalid-size:/name}.
test-epilogue: null
test-prologue: null
- name: Count
states:
- name: Zero
test-code: |
T_eq_u32( ctx->count, 0 );
text: |
The value of the object referenced by the
${../if/broadcast:/params[3]/name} parameter shall be set to 0 after
the return of the ${../if/broadcast:/name} call.
- name: Set
test-code: |
T_eq_u32( ctx->count, NUMBER_OF_WORKERS );
text: |
The value of the object referenced by the
${../if/broadcast:/params[3]/name} parameter shall be set to the number
of tasks unblocked (see ${../glossary/unblock:/term}) by the call
to directive ${../if/broadcast:/name} after the
return of the ${../if/broadcast:/name} call.
- name: Nop
test-code: |
T_eq_u32( ctx->count, UINT8_MAX );
text: |
The value of the object referenced by the
${../if/broadcast:/params[3]/name}
parameter in past call to ${../if/broadcast:/name} shall not be
accessed by the ${../if/broadcast:/name} call
(see also ${../glossary/nop:/term}).
test-epilogue: null
test-prologue: null
- name: MsgQueue
states:
- name: Nop
test-code: |
ctx->check_msgq_unchanged( ctx );
text: |
Objects referenced by the ${../if/broadcast:/params[0]/name}
parameter in the past call to ${../if/broadcast:/name} shall not be
accessed by that call (see also ${../glossary/nop:/term}).
test-epilogue: null
test-prologue: null
- name: Receivers
states:
- name: Unblocked
test-code: |
for ( i = 0; i < NUMBER_OF_WORKERS; ++i ) {
T_rsc_success( ctx->receive_status[i] );
}
text: |
The call to the ${../if/broadcast:/name} directive shall
${../glossary/unblock:/term} all ${../glossary/receiver:/plural}
waiting for a message at the ${/glossary/messagequeue:/term}.
Note: Currently, ${../if/broadcast:/name} unblocks
${../glossary/receiver:/plural} in a none-atomic way. Meaning,
it will not only ${../glossary/unblock:/term} those
${../glossary/receiver:/plural} it finds waiting at the queue
when ${../if/broadcast:/name} is invoked but also any new
${../glossary/receiver:/plural} which start waiting for
messages after ${../if/broadcast:/name} is invoked and
before it returns. This may lead to infinite unblocking loops.
- name: Nop
test-code: |
for ( i = 0; i < NUMBER_OF_WORKERS; ++i ) {
T_rsc( ctx->receive_status[i], RTEMS_TIMEOUT );
}
text: |
The ${../glossary/receiver:/plural} waiting for
a message at the ${/glossary/messagequeue:/term} shall not be affected
by the call to the ${../if/broadcast:/name} directive.
test-epilogue: null
test-prologue: |
size_t i;
- name: RecSize
states:
- name: Message
test-code: |
for ( i = 0; i < NUMBER_OF_WORKERS; ++i ) {
CheckForMessage(
ctx,
ctx->receive_status[i],
ctx->receive_buffer[i],
ctx->receive_size[i]
);
}
text: |
The values of the objects referenced by the
${../if/receive:/params[2]/name} parameter in all calls to
${../if/receive:/name} which are unblocked (see
${../glossary/unblock:/term}) by the ${../if/broadcast:/name}
call shall be set to the same value as provided by parameter
${../if/broadcast:/params[2]/name} of the ${../if/broadcast:/name}
call after the return of the ${../if/broadcast:/name} call.
- name: Nop
test-code: |
for ( i = 0; i < NUMBER_OF_WORKERS; ++i ) {
T_eq_sz( ctx->receive_size[i], 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/broadcast:/name} call (see also
${../glossary/nop:/term}).
test-epilogue: null
test-prologue: |
size_t i;
- name: RecBuffer
states:
- name: Message
test-code: |
for ( i = 0; i < NUMBER_OF_WORKERS; ++i ) {
CheckForMessage(
ctx,
ctx->receive_status[i],
ctx->receive_buffer[i],
ctx->receive_size[i]
);
}
text: |
Bytes 0 till ${../if/receive:/params[2]/name} - 1 of the object
referenced by the ${../if/receive:/params[1]/name} parameter in all
calls to ${../if/receive:/name} which are unblocked (see
${../glossary/unblock:/term}) by the ${../if/broadcast:/name}
call shall be set to the same values as bytes 0 till
${../if/receive:/params[2]/name} - 1 of the object
referenced by parameter ${../if/broadcast:/params[1]/name} of the
${../if/broadcast:/name} call after the return of the
${../if/receive:/name} call.
- name: Nop
test-code: |
for ( w = 0; w < NUMBER_OF_WORKERS; ++w ) {
for ( i = 0; i < MAXIMUM_MESSAGE_SIZE; ++i ) {
T_eq_u8( ctx->receive_buffer[w][i], UINT8_MAX );
}
}
text: |
Objects referenced by the ${../if/receive:/params[1]/name}
parameter in past calls to ${../if/receive:/name} shall not be
accessed by the ${../if/broadcast:/name} call (see also
${../glossary/nop:/term}).
test-epilogue: null
test-prologue: |
size_t w, i;
pre-conditions:
- name: SendBuffer
states:
- name: Valid
test-code: |
ctx->buffer_param = &message;
text: |
While the ${../if/broadcast:/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/broadcast:/params[1]/name} parameter is
${/c/if/null:/name}.
test-epilogue: null
test-prologue: null
- name: Count
states:
- name: Valid
test-code: |
ctx->count_param = &ctx->count;
text: |
While the ${../if/broadcast:/params[3]/name} parameter references
an ``uint32_t`` object.
- name: 'Null'
test-code: |
ctx->count_param = NULL;
text: |
While the ${../if/broadcast:/params[3]/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/broadcast:/params[0]/name} parameter is valid.
- name: Invalid
test-code: |
ctx->id_param = RTEMS_ID_NONE;
text: |
While the ${../if/broadcast:/params[0]/name} parameter is invalid.
test-epilogue: null
test-prologue: null
- name: MsgSize
states:
- name: Zero
test-code: |
ctx->size_param = 0;
text: |
While the ${../if/broadcast:/params[2]/name} parameter is 0.
- name: SomeSize
test-code: |
ctx->size_param = MAXIMUM_MESSAGE_SIZE / 2 + 1;
text: |
While the ${../if/broadcast:/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/broadcast:/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/broadcast:/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: Several
test-code: |
SendMsg( ctx );
SendMsg( ctx );
ctx->check_msgq_unchanged = CheckForSeveralMessagesInQueue;
text: |
While there are messages in the ${/glossary/messagequeue:/term}.
test-epilogue: null
test-prologue: null
- name: Receivers
states:
- name: Waiting
test-code: |
size_t i;
for ( i = 0; i < NUMBER_OF_WORKERS; ++i ) {
SendEvents( ctx->worker_id[i], EVENT_RECEIVE );
}
text: |
While one or more ${../glossary/receiver:/plural} are waiting to
receive a message.
- name: None
test-code: |
/* There is already no receiver waiting. */
text: |
While no ${../glossary/receiver:/term} is waiting to receive a message.
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: |
ctx->status = rtems_message_queue_broadcast(
ctx->id_param,
ctx->buffer_param,
ctx->size_param,
ctx->count_param
);
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 a buffer to receive messages from the queue.
description: null
member: |
uint8_t receive_buffer[ NUMBER_OF_WORKERS ][ MAXIMUM_MESSAGE_SIZE ]
- brief: |
This member contains several buffers to receive a messages size.
description: null
member: |
size_t receive_size[ NUMBER_OF_WORKERS ]
- brief: |
This member contains the returned ${/glossary/statuscode:/plural}
of the receivers.
description: null
member: |
rtems_status_code receive_status[ NUMBER_OF_WORKERS ]
- brief: |
This member specifies the ${../if/broadcast:/params[0]/name} parameter
of the action.
description: null
member: |
rtems_id id_param
- brief: |
This member specifies the ${../if/broadcast:/params[1]/name} parameter
of the action.
description: null
member: |
const void *buffer_param
- brief: |
This member specifies the ${../if/broadcast:/params[2]/name} parameter
of the action.
description: null
member: |
size_t size_param
- brief: |
This member specifies the ${../if/broadcast:/params[3]/name} parameter
of the action.
description: null
member: |
uint32_t *count_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 value returned in parameter
${../if/broadcast:/params[3]/name} of the action.
description: null
member: |
uint32_t count
- brief: |
This member contains the ${/glossary/task:/term} identifiers of the
worker ${/glossary/task:/plural}.
description: null
member: |
rtems_id worker_id[ NUMBER_OF_WORKERS ]
- 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
#define NUMBER_OF_WORKERS 3
test-description: null
test-header: null
test-includes:
- rtems.h
test-local-includes:
- tx-support.h
test-prepare: |
rtems_status_code status;
size_t i;
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 );
ctx->count = UINT8_MAX;
for ( i = 0; i < NUMBER_OF_WORKERS; ++i ) {
ctx->receive_size[i] = SIZE_MAX;
memset( ctx->receive_buffer[i], UINT8_MAX, MAXIMUM_MESSAGE_SIZE );
}
test-setup:
brief: null
code: |
size_t i;
SetSelfPriority( PRIO_NORMAL );
for ( i = 0; i < NUMBER_OF_WORKERS; ++i ) {
ctx->worker_id[i] = CreateTask( "WORK", PRIO_HIGH );
StartTask( ctx->worker_id[i], WorkerTask, ctx );
}
description: null
test-stop: null
test-support: |
typedef ${.:/test-context-type} Context;
static const rtems_interval TIMEOUT_TICKS = 1;
static const rtems_event_set EVENT_RECEIVE = RTEMS_EVENT_17;
static const uint8_t message[ MAXIMUM_MESSAGE_SIZE ] =
{ 13, 42, 99, 222, 101 };
static const uint8_t queued_message[] = { 200, 201, 202 };
static void Receive( Context *ctx, size_t worker_index )
{
ctx->receive_status[worker_index] = rtems_message_queue_receive(
ctx->message_queue_id,
ctx->receive_buffer[worker_index],
&ctx->receive_size[worker_index],
RTEMS_WAIT,
TIMEOUT_TICKS
);
}
static void WorkerTask( rtems_task_argument argument )
{
static size_t worker_number = 0;
size_t worker_index = worker_number++;
Context *ctx = (Context *) argument;
while ( true ) {
ReceiveAnyEvents();
Receive( ctx, worker_index );
}
}
static void CheckForNoMessage(
Context *ctx,
rtems_status_code status,
uint8_t *message_buffer,
size_t message_size
)
{
(void) ctx;
(void) message_buffer;
(void) message_size;
T_rsc( status, RTEMS_UNSATISFIED );
}
static void CheckForMessage(
Context *ctx,
rtems_status_code status,
uint8_t *message_buffer,
size_t message_size
)
{
T_rsc_success( status );
T_eq_u32( message_size, ctx->size_param );
T_eq_mem( message_buffer, message, ctx->size_param );
}
static void CheckForQueuedMessage(
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, sizeof( queued_message ) );
T_eq_mem( message_buffer, queued_message, sizeof( queued_message ) );
}
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 )
{
Context *ctx = ctx_in;
PopMessage( ctx, CheckForNoMessage );
}
static void CheckForSeveralMessagesInQueue( void *ctx_in )
{
Context *ctx = ctx_in;
PopMessage( ctx, CheckForQueuedMessage );
PopMessage( ctx, CheckForQueuedMessage );
PopMessage( ctx, CheckForNoMessage );
}
static void SendMsg( Context *ctx )
{
rtems_status_code status;
status = rtems_message_queue_send(
ctx->message_queue_id,
queued_message,
sizeof( queued_message )
);
T_rsc_success( status );
}
test-target: testsuites/validation/tc-message-broadcast.c
test-teardown:
brief: null
code: |
size_t i;
for ( i = 0; i < NUMBER_OF_WORKERS; ++i ) {
DeleteTask( ctx->worker_id[i] );
}
RestoreRunnerPriority();
description: null
text: ${.:text-template}
transition-map:
# ---- Ok Case ----
- enabled-by: true
post-conditions:
Status: Ok
Count:
- if:
pre-conditions:
Receivers: Waiting
then: Set
- else: Zero
MsgQueue: Nop
Receivers:
- if:
pre-conditions:
Receivers: Waiting
then: Unblocked
- else: N/A
RecSize:
- if:
pre-conditions:
Receivers: Waiting
then: Message
- else: N/A
RecBuffer:
- if:
pre-conditions:
Receivers: Waiting
then: Message
- else: N/A
pre-conditions:
SendBuffer:
- Valid
Count:
- Valid
Id:
- Valid
MsgSize:
- Zero
- SomeSize
- MaxSize
MsgQueue: all
Receivers: all
Storage: all
# ---- InvAddr: SendBuffer ----
- enabled-by: true
post-conditions:
Status: InvAddr
Count: Nop
MsgQueue: Nop
Receivers:
- if:
pre-conditions:
Receivers: Waiting
then: Nop
- else: N/A
RecSize:
- if:
pre-conditions:
Receivers: Waiting
then: Nop
- else: N/A
RecBuffer:
- if:
pre-conditions:
Receivers: Waiting
then: Nop
- else: N/A
pre-conditions:
SendBuffer:
- 'Null'
Count: all
Id: all
MsgSize: all
MsgQueue: all
Receivers: all
Storage: all
# ---- InvAddr: Count ----
- enabled-by: true
post-conditions:
Status: InvAddr
Count: Nop
MsgQueue: Nop
Receivers:
- if:
pre-conditions:
Receivers: Waiting
then: Nop
- else: N/A
RecSize:
- if:
pre-conditions:
Receivers: Waiting
then: Nop
- else: N/A
RecBuffer:
- if:
pre-conditions:
Receivers: Waiting
then: Nop
- else: N/A
pre-conditions:
SendBuffer:
- Valid
Count:
- 'Null'
Id: all
MsgSize: all
MsgQueue: all
Receivers: all
Storage: all
# ---- InvId ----
- enabled-by: true
post-conditions:
Status: InvId
Count: Nop
MsgQueue: Nop
Receivers:
- if:
pre-conditions:
Receivers: Waiting
then: Nop
- else: N/A
RecSize:
- if:
pre-conditions:
Receivers: Waiting
then: Nop
- else: N/A
RecBuffer:
- if:
pre-conditions:
Receivers: Waiting
then: Nop
- else: N/A
pre-conditions:
SendBuffer:
- Valid
Count:
- Valid
Id:
- Invalid
MsgSize: all
MsgQueue: all
Receivers: all
Storage: all
# ---- InvSize ----
- enabled-by: true
post-conditions:
Status: InvSize
Count: Nop
MsgQueue: Nop
Receivers:
- if:
pre-conditions:
Receivers: Waiting
then: Nop
- else: N/A
RecSize:
- if:
pre-conditions:
Receivers: Waiting
then: Nop
- else: N/A
RecBuffer:
- if:
pre-conditions:
Receivers: Waiting
then: Nop
- else: N/A
pre-conditions:
SendBuffer:
- Valid
Count:
- Valid
Id:
- Valid
MsgSize:
- TooLarge
MsgQueue: all
Receivers: all
Storage: all
# ---- Impossible Cases ----
- enabled-by: true
post-conditions: NoWait
pre-conditions:
SendBuffer: all
Count: all
Id: all
MsgSize: all
MsgQueue:
- Several
Receivers:
- Waiting
Storage: all
type: requirement