From: Lou Woods <lou.wo...@oarcorp.com> This test exercises the unblocking order of a POSIX message queue
-Added psxmsgq05 test to the make structure. -Added tests, doc, and scn output. updates #3791. --- testsuites/psxtests/Makefile.am | 10 + testsuites/psxtests/configure.ac | 1 + testsuites/psxtests/psxmsgq05/init.c | 440 ++++++++++++++++++++++++++++ testsuites/psxtests/psxmsgq05/psxmsgq05.doc | 42 +++ testsuites/psxtests/psxmsgq05/psxmsgq05.scn | 4 + testsuites/psxtests/psxmsgq05/system.h | 56 ++++ 6 files changed, 553 insertions(+) mode change 100755 => 100644 testsuites/psxtests/Makefile.am create mode 100644 testsuites/psxtests/psxmsgq05/init.c create mode 100644 testsuites/psxtests/psxmsgq05/psxmsgq05.doc create mode 100644 testsuites/psxtests/psxmsgq05/psxmsgq05.scn create mode 100644 testsuites/psxtests/psxmsgq05/system.h diff --git a/testsuites/psxtests/Makefile.am b/testsuites/psxtests/Makefile.am old mode 100755 new mode 100644 index c12b036..52c9644 --- a/testsuites/psxtests/Makefile.am +++ b/testsuites/psxtests/Makefile.am @@ -685,6 +685,16 @@ psxmsgq04_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_psxmsgq04) \ $(support_includes) -I$(top_srcdir)/include endif +if TEST_psxmsgq05 +psx_tests += psxmsgq05 +psx_screens += psxmsgq05/psxmsgq05.scn +psx_docs += psxmsgq05/psxmsgq05.doc +psxmsgq05_SOURCES = psxmsgq05/init.c psxmsgq05/system.h \ + include/pmacros.h ../support/src/test_support.c +psxmsgq05_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_psxmsgq05) \ + $(support_includes) -I$(top_srcdir)/include +endif + if TEST_psxmutexattr01 psx_tests += psxmutexattr01 psx_screens += psxmutexattr01/psxmutexattr01.scn diff --git a/testsuites/psxtests/configure.ac b/testsuites/psxtests/configure.ac index bb44bb8..32d143a 100644 --- a/testsuites/psxtests/configure.ac +++ b/testsuites/psxtests/configure.ac @@ -112,6 +112,7 @@ RTEMS_TEST_CHECK([psxmsgq01]) RTEMS_TEST_CHECK([psxmsgq02]) RTEMS_TEST_CHECK([psxmsgq03]) RTEMS_TEST_CHECK([psxmsgq04]) +RTEMS_TEST_CHECK([psxmsgq05]) RTEMS_TEST_CHECK([psxmutexattr01]) RTEMS_TEST_CHECK([psxndbm01]) RTEMS_TEST_CHECK([psxobj01]) diff --git a/testsuites/psxtests/psxmsgq05/init.c b/testsuites/psxtests/psxmsgq05/init.c new file mode 100644 index 0000000..ab06156 --- /dev/null +++ b/testsuites/psxtests/psxmsgq05/init.c @@ -0,0 +1,440 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (C) 2019 On-Line Applications Research. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define CONFIGURE_INIT +#include "system.h" + +#include <fcntl.h> /* For O_* constants */ +#include <pthread.h> +#include <semaphore.h> +#include <mqueue.h> +#include <sched.h> + +#include "test_support.h" + +const char rtems_test_name[] = "PSXMSGQ 5"; + +#define DEFAULT_WAIT 5 +#define DEFAULT_BUFFER_SIZE 4 +#define TASKS 2 + +struct task_args { + mqd_t *p_main_msgQ; + sem_t *p_task_sem; + int wait_timeout; + bool receive_test; +}; + +/* forward declarations to avoid warnings */ +static int test_msgQ_unblock_order( + bool receive_test, /* true to test receive order, false for + send order */ + bool *task1_released, /* set by function to indicate task1 was + released */ + bool *task2_released /* set by function to indicate task2 was + released */ +); +static void *taskEntry( void *arg ); + +/* The taskEntry function calls send or receive on the provided message queue + * and will block waiting to receive or send a message depending on the + * receive_test flag. Once the tasked is unblocked it will post the provided + * semaphore. + */ +static void *taskEntry( void *arg ) +{ + char buffer[ DEFAULT_BUFFER_SIZE ]; + struct timespec timeout; + int retval; + struct task_args *args = arg; + + if ( args == NULL ) { + fprintf( stderr, "NULL argument passed to task, exiting\n" ); + + return NULL; + } + +#if 0 + fprintf( stderr, + "task id %x with sem %x about to block\n", + pthread_self(), + (unsigned int) ( args->p_task_sem ) ); +#endif + + if ( args->receive_test == true ) { + if ( args->wait_timeout != 0 ) { + retval = clock_gettime( CLOCK_REALTIME, &timeout ); + + if ( retval == ( -1 ) ) { + perror( "clock gettime failed" ); + + return NULL; + } + + timeout.tv_sec += args->wait_timeout; + retval = mq_timedreceive( *( args->p_main_msgQ ), + buffer, + DEFAULT_BUFFER_SIZE, + NULL, + &timeout ); + + if ( retval == ( -1 ) ) { + perror( "time mq_receive returned unexpectedly." ); + + return NULL; + } + } else { + retval = mq_receive( *( args->p_main_msgQ ), + buffer, + DEFAULT_BUFFER_SIZE, + NULL ); + + if ( retval == ( -1 ) ) { + perror( "time mq_receive returned unexpectedly." ); + + return NULL; + } + } + } else { + if ( args->wait_timeout != 0 ) { + retval = clock_gettime( CLOCK_REALTIME, &timeout ); + + if ( retval == ( -1 ) ) { + perror( "clock gettime failed" ); + + return NULL; + } + + timeout.tv_sec += args->wait_timeout; + retval = mq_timedsend( *( args->p_main_msgQ ), + buffer, + DEFAULT_BUFFER_SIZE, + 1, + &timeout ); + + if ( retval == ( -1 ) ) { + perror( "time mq_send returned unexpectedly." ); + + return NULL; + } + } else { + retval = mq_send( *( args->p_main_msgQ ), + buffer, + DEFAULT_BUFFER_SIZE, + 1 ); + + if ( retval == ( -1 ) ) { + perror( "time mq_send returned unexpectedly." ); + + return NULL; + } + } + } + + retval = sem_post( args->p_task_sem ); + + if ( retval == ( -1 ) ) { + perror( "sem_post failed from the task" ); + } + +#if 0 + fprintf( stderr, + "given task sem %x\n", + (unsigned int) args->p_task_sem ); + fflush( stderr ); +#endif + + return NULL; +} + +/* The theory of operation for test_msgQ_unblock_order is to get two + * tasks to block on a message queue in FIFO order and demonstrate that they + * are released in priority order. This will test blocking on message queue + * receive when receive_test is set to true otherwise it will test blocking + * on a message queue send call. A message queue of size of 1 is created and + * shared between the main thread and two worker threads. For the receive + * blocking case the main thread will wait for the two threads to come up and + * call receive on the queue. The lower priority task is allowed to come up + * first and call receive before the higher priority task. The main task will + * now send a message to the shared queue and see which thread posts its + * semaphore indicating which task was woken up. If the higher priority task + * posts its semaphore then the test is a success. The send unblock order works + * similarly but the main task must fill the message queue first and call + * receive once the two threads are blocked on their send call. + */ +static int test_msgQ_unblock_order( + bool receive_test, + bool *task1_released, + bool *task2_released +) +{ + pthread_t task_id[ TASKS ]; + const int task_priority[ TASKS ] = { 50, 60 }; + struct sched_param task_params[ TASKS ]; + pthread_attr_t task_attr[ TASKS ]; + struct task_args task_args[ TASKS ]; + sem_t task_sem[ TASKS ]; + const int task_self_priority = 40; + pthread_t task_self; + struct sched_param self_params; + mqd_t main_msgQ; + struct mq_attr mq_attribs; + struct timespec no_wait_tmo; + int retval; + int success = 0; + size_t lcv; + char buffer[] = { '1', '2', '3', '4' }; + const char mq_name[] = "/psxmq5"; + + if ( task1_released != NULL ) + *task1_released = false; + else + return -1; + + if ( task2_released != NULL ) + *task2_released = false; + else + return -1; + + memset( &no_wait_tmo, 0, sizeof( no_wait_tmo ) ); + + task_self = pthread_self(); + mq_attribs.mq_maxmsg = 1; + mq_attribs.mq_msgsize = DEFAULT_BUFFER_SIZE; + + main_msgQ = mq_open( mq_name, + O_CREAT | O_RDWR | O_EXCL, + 0666, + &mq_attribs ); + + if ( main_msgQ == ( -1 ) ) { + perror( "mq_open failed" ); + + return -1; + } + + for ( lcv = 0; lcv < TASKS; lcv++ ) { + retval = sem_init( &task_sem[ lcv ], 0, 0 ); + + if ( retval == ( -1 ) ) { + perror( "semaphore creation failed" ); + + return -1; + } + } + + self_params.sched_priority = task_self_priority; + retval = pthread_setschedparam( task_self, SCHED_FIFO, &self_params ); + + if ( retval == ( -1 ) ) { + perror( "failed to set main task priority" ); + + return -1; + } + + if ( receive_test == false ) { + /* fill up the queue */ + retval = mq_send( main_msgQ, buffer, DEFAULT_BUFFER_SIZE, 1 ); + + if ( retval == ( -1 ) ) { + perror( "mq_send failed to fill queue" ); + + return -1; + } + } + + for ( lcv = 0; lcv < TASKS; lcv++ ) { + /* Task are put into the wait state in FIFO order */ + task_params[ lcv ].sched_priority = task_priority[ lcv ]; + pthread_attr_init( &task_attr[ lcv ] ); + pthread_attr_setinheritsched( &task_attr[ lcv ], PTHREAD_EXPLICIT_SCHED ); + pthread_attr_setschedpolicy( &task_attr[ lcv ], SCHED_FIFO ); + pthread_attr_setschedparam( &task_attr[ lcv ], &task_params[ lcv ] ); + pthread_attr_setdetachstate( &task_attr[ lcv ], PTHREAD_CREATE_DETACHED ); + + task_args[ lcv ].p_main_msgQ = &main_msgQ; + task_args[ lcv ].p_task_sem = &task_sem[ lcv ]; + task_args[ lcv ].wait_timeout = DEFAULT_WAIT; + task_args[ lcv ].receive_test = receive_test; + + retval = pthread_create( &task_id[ lcv ], + &task_attr[ lcv ], + &taskEntry, + (void *) &task_args[ lcv ] ); + + if ( retval == ( -1 ) ) { + perror( "pthread_create failed for task" ); + + return -1; + } + + sched_yield(); + } + + sleep( 1 ); +#if 0 + fprintf( stderr, + "task1 id %x sem %x; task2 id %x sem %x\n", + task_id[ 0 ], + (unsigned int) &task_sem[ 0 ], + task_id[ 1 ], + (unsigned int) &task_sem[ 1 ] ); +#endif + + if ( receive_test == true ) { + retval = mq_timedsend( main_msgQ, + buffer, + DEFAULT_BUFFER_SIZE, + 1, + &no_wait_tmo ); + + if ( retval == ( -1 ) ) { + perror( "mq_send failed to add item" ); + + return -1; + } + } else { + retval = mq_timedreceive( main_msgQ, + buffer, + DEFAULT_BUFFER_SIZE, + NULL, + &no_wait_tmo ); + + if ( retval == ( -1 ) ) { + perror( "mq_receive failed to retrieve item" ); + + return -1; + } + } + + sched_yield(); + + retval = sem_timedwait( &task_sem[ 0 ], &no_wait_tmo ); + + if ( retval == ( -1 ) && errno == ETIMEDOUT ) + *task1_released = false; + else if ( retval == 0 ) + *task1_released = true; + else + success = -1; + + retval = sem_timedwait( &task_sem[ 1 ], &no_wait_tmo ); + + if ( retval == ( -1 ) && errno == ETIMEDOUT ) + *task2_released = false; + else if ( retval == ( 0 ) ) + *task2_released = true; + else + success = -1; + + /* clean up the remaining thread */ + if ( receive_test == true ) { + mq_timedsend( main_msgQ, + buffer, + DEFAULT_BUFFER_SIZE, + 1, + &no_wait_tmo ); + } else { + mq_timedreceive( main_msgQ, + buffer, + DEFAULT_BUFFER_SIZE, + NULL, + &no_wait_tmo ); + } + + sched_yield(); + + for ( lcv = 0; lcv < TASKS; lcv++ ) { + retval = pthread_cancel( task_id[ lcv ] ); + + if ( retval == ( -1 ) ) + perror( "failed to cancel task" ); + + retval = sem_destroy( &task_sem[ lcv ] ); + + if ( retval == ( -1 ) ) + perror( "failed to delete semaphore" ); + } + + retval = mq_close( main_msgQ ); + + if ( retval == ( -1 ) ) + perror( "failed to close message queue" ); + + retval = mq_unlink( mq_name ); + + if ( retval == ( -1 ) ) + perror( "failed to unlink message queue" ); + + return success; +} + +/* This test demonstrates the unblock order of the POSIX message queue + * when two threads are forced to block on the same message queue call. The + * expected behavior is for the higher priority thread to be unblocked and + * receive a message ahead of a lower priority thread also blocked on a receive + * call. The behavior is expected to be the same when two or more threads + * attempt to send at the same time and have to block. This test does not + * address message priority + */ +void *POSIX_Init( void *argument ) +{ + int success; + bool task1_released; + bool task2_released; + + TEST_BEGIN(); + + puts( "Init - send priority unblock order" ); + + success = test_msgQ_unblock_order( + false, + &task1_released, + &task2_released ); + rtems_test_assert( success == ( 0 ) ); + + rtems_test_assert( task2_released == true && task1_released == false ); + + puts( "Init - receive priority unblock order" ); + + success = test_msgQ_unblock_order( + true, + &task1_released, + &task2_released ); + rtems_test_assert( success == ( 0 ) ); + + rtems_test_assert( task2_released == true && task1_released == false ); + + TEST_END(); + rtems_test_exit( 0 ); + + return NULL; /* just so the compiler thinks we returned something */ +} diff --git a/testsuites/psxtests/psxmsgq05/psxmsgq05.doc b/testsuites/psxtests/psxmsgq05/psxmsgq05.doc new file mode 100644 index 0000000..e9eae49 --- /dev/null +++ b/testsuites/psxtests/psxmsgq05/psxmsgq05.doc @@ -0,0 +1,42 @@ +# +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (C) 2019 On-Line Applications Research. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +This file describes the directives and concepts tested by this test set. + +test set name: psxmsgq05 + +directives: + + mq_send + mq_timedsend + mq_receive + mq_timedreceive + +concepts: + ++ Ensure that threads are unblocked in priority order while waiting to send or + receive a queued message. diff --git a/testsuites/psxtests/psxmsgq05/psxmsgq05.scn b/testsuites/psxtests/psxmsgq05/psxmsgq05.scn new file mode 100644 index 0000000..9c43710 --- /dev/null +++ b/testsuites/psxtests/psxmsgq05/psxmsgq05.scn @@ -0,0 +1,4 @@ +*** POSIX MESSAGE QUEUE TEST 5 *** +Init - send priority unblock order +Init - receive priority unblock order +*** END OF POSIX MESSAGE QUEUE TEST 5 *** diff --git a/testsuites/psxtests/psxmsgq05/system.h b/testsuites/psxtests/psxmsgq05/system.h new file mode 100644 index 0000000..28e68f9 --- /dev/null +++ b/testsuites/psxtests/psxmsgq05/system.h @@ -0,0 +1,56 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (C) 2019 On-Line Applications Research. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* functions */ + +#include <pmacros.h> +#include <unistd.h> +#include <errno.h> +#include <sched.h> +#include <tmacros.h> + +void *POSIX_Init( + void *argument +); + +/* configuration information */ + +#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER + +#define CONFIGURE_POSIX_INIT_THREAD_TABLE + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_MAXIMUM_POSIX_THREADS 3 +#define CONFIGURE_MAXIMUM_POSIX_MESSAGE_QUEUES 1 +#define CONFIGURE_MAXIMUM_TIMERS 1 + +#define CONFIGURE_POSIX_INIT_THREAD_TABLE + +#include <rtems/confdefs.h> +/* end of include file */ -- 1.8.3.1 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel