[PATCH 1/2] psxmsgq05: Added priority unblocking mq tests

Lou Woods irnhorse4 at gmail.com
Thu Aug 29 18:11:25 UTC 2019


From: Lou Woods <Lou.Woods at 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



More information about the devel mailing list