This is an automated email from the ASF dual-hosted git repository.

jerpelea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git


The following commit(s) were added to refs/heads/master by this push:
     new f04aee601 testing/testsuites: Add a System V message queue test.
f04aee601 is described below

commit f04aee6015cb1fda8d33b768c57ccb344d0826b0
Author: Marco Casaroli <[email protected]>
AuthorDate: Wed Nov 4 12:08:42 2026 +0100

    testing/testsuites: Add a System V message queue test.
    
    No test in apps covers msgget(), msgsnd(), msgrcv() and msgctl().  Add
    the cmocka test cmocka_msg_test (CONFIG_CM_MSG_TEST, needs System V
    message queues and pthreads).  It checks:
    
    - msgget(IPC_PRIVATE) with and without IPC_CREAT.  msgget() of a key
      gives the same identifier again, and EEXIST with IPC_CREAT | IPC_EXCL.
      More than 250 queues at the same time.
    - msgrcv() with msgtyp 0, greater than 0 and less than 0 (ENOMSG with
      IPC_NOWAIT when no type is <= |msgtyp|).
    - MSG_NOERROR truncation, E2BIG (the message stays in the queue),
      ENOMSG and EAGAIN with IPC_NOWAIT, and EINVAL.
    - msgctl() IPC_STAT (all fields), IPC_SET (msg_qbytes in bytes) and
      IPC_RMID.
    - A blocked msgrcv() or msgsnd() returns when msgsnd() or msgrcv() of
      another thread gives it a message or room, fails with EIDRM when the
      queue is removed, and fails with EINTR when a signal interrupts it.
      A message goes to the waiter of its type.
    - msgsnd() with an empty message pool (CONFIG_PREALLOC_MQ_MSGS): EAGAIN
      with IPC_NOWAIT, blocks until msgrcv() frees a message, EINTR, EIDRM.
    
    The CMake rules of the suites are in kernel/CMakeLists.txt, which this
    commit updates [skip-cmake-parity].
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 testing/testsuites/Kconfig                         |   8 +
 testing/testsuites/Makefile                        |   8 +
 testing/testsuites/kernel/CMakeLists.txt           |  21 ++
 testing/testsuites/kernel/msg/cases/msg_test_ctl.c | 168 +++++++++++++
 testing/testsuites/kernel/msg/cases/msg_test_get.c | 152 ++++++++++++
 .../testsuites/kernel/msg/cases/msg_test_pool.c    | 186 ++++++++++++++
 .../testsuites/kernel/msg/cases/msg_test_size.c    | 161 ++++++++++++
 .../testsuites/kernel/msg/cases/msg_test_type.c    | 141 +++++++++++
 .../testsuites/kernel/msg/cases/msg_test_wait.c    | 275 +++++++++++++++++++++
 testing/testsuites/kernel/msg/cmocka_msg_test.c    |  77 ++++++
 .../testsuites/kernel/msg/common/test_msg_common.c | 240 ++++++++++++++++++
 testing/testsuites/kernel/msg/include/MsgTest.h    | 145 +++++++++++
 12 files changed, 1582 insertions(+)

diff --git a/testing/testsuites/Kconfig b/testing/testsuites/Kconfig
index 5c909505e..32559d89c 100644
--- a/testing/testsuites/Kconfig
+++ b/testing/testsuites/Kconfig
@@ -62,5 +62,13 @@ config CM_MUTEX_TEST
        bool "enable mutex test"
        default n
 
+config CM_MSG_TEST
+       bool "enable System V message queue test"
+       default n
+       depends on !DISABLE_MQUEUE_SYSV && !DISABLE_PTHREAD
+       depends on PREALLOC_MQ_MSGS >= 4 && MQ_MAXMSGSIZE >= 8
+       ---help---
+               Test msgget(), msgsnd(), msgrcv() and msgctl().
+
 endmenu
 endif # TESTS_TESTSUITES
diff --git a/testing/testsuites/Makefile b/testing/testsuites/Makefile
index ac63f2164..406dab545 100644
--- a/testing/testsuites/Makefile
+++ b/testing/testsuites/Makefile
@@ -86,6 +86,14 @@ PROGNAME += cmocka_socket_test
 MAINSRC += $(CURDIR)/kernel/socket/cmocka_socket_test.c
 endif
 
+ifneq ($(CONFIG_CM_MSG_TEST),)
+CFLAGS += -I$(CURDIR)/kernel/msg/include
+CSRCS += $(wildcard kernel/msg/cases/*.c)
+CSRCS += $(wildcard kernel/msg/common/*.c)
+PROGNAME += cmocka_msg_test
+MAINSRC += $(CURDIR)/kernel/msg/cmocka_msg_test.c
+endif
+
 ifneq ($(CONFIG_CM_SYSCALL_TEST),)
 CFLAGS += -I$(CURDIR)/kernel/syscall/include
 CFLAGS += -I$(APPDIR)/nshlib
diff --git a/testing/testsuites/kernel/CMakeLists.txt 
b/testing/testsuites/kernel/CMakeLists.txt
index ce7f042cb..03a6c24f3 100644
--- a/testing/testsuites/kernel/CMakeLists.txt
+++ b/testing/testsuites/kernel/CMakeLists.txt
@@ -211,3 +211,24 @@ if(CONFIG_CM_MUTEX_TEST)
     DEPENDS
     cmocka)
 endif()
+
+if(CONFIG_CM_MSG_TEST)
+  set(INCDIR ${CMAKE_CURRENT_SOURCE_DIR}/msg/include
+             ${NUTTX_DIR}/../apps/testing/cmocka/include)
+  file(GLOB MSG_CSRCS ${CMAKE_CURRENT_SOURCE_DIR}/msg/cases/*.c
+       ${CMAKE_CURRENT_SOURCE_DIR}/msg/common/*.c)
+  nuttx_add_application(
+    NAME
+    cmocka_msg_test
+    STACKSIZE
+    ${CONFIG_TESTS_TESTSUITES_STACKSIZE}
+    PRIORITY
+    ${CONFIG_TESTS_TESTSUITES_PRIORITY}
+    SRCS
+    msg/cmocka_msg_test.c
+    ${MSG_CSRCS}
+    INCLUDE_DIRECTORIES
+    ${INCDIR}
+    DEPENDS
+    cmocka)
+endif()
diff --git a/testing/testsuites/kernel/msg/cases/msg_test_ctl.c 
b/testing/testsuites/kernel/msg/cases/msg_test_ctl.c
new file mode 100644
index 000000000..737ea1b4f
--- /dev/null
+++ b/testing/testsuites/kernel/msg/cases/msg_test_ctl.c
@@ -0,0 +1,168 @@
+/****************************************************************************
+ * apps/testing/testsuites/kernel/msg/cases/msg_test_ctl.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "MsgTest.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: test_nuttx_msg_ctl_stat
+ *
+ * Description:
+ *   IPC_STAT gives the number of messages and the size limit of the queue.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_ctl_stat(FAR void **state)
+{
+  struct msg_test_buf_s buf;
+  struct msqid_ds ds;
+  int id;
+
+  id = msg_test_create(IPC_PRIVATE, 0600);
+  assert_true(id >= 0);
+
+  memset(&ds, 0xff, sizeof(ds));
+  assert_int_equal(msgctl(id, IPC_STAT, &ds), 0);
+  assert_int_equal(ds.msg_qnum, 0);
+  assert_true(ds.msg_qbytes >= MSG_TEST_MAXSIZE);
+
+  assert_int_equal(msg_test_send(id, 1, "a", 1, 0), 0);
+  assert_int_equal(msg_test_send(id, 2, "b", 1, 0), 0);
+  assert_int_equal(msg_test_qnum(id), 2);
+
+  assert_int_equal(msg_test_recv(id, &buf, 1, 0, 0), 1);
+  assert_int_equal(msg_test_qnum(id), 1);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_ctl_fields
+ *
+ * Description:
+ *   IPC_STAT gives the permissions, the process IDs and the times of the
+ *   last msgsnd() and msgrcv().
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_ctl_fields(FAR void **state)
+{
+  struct msg_test_buf_s buf;
+  struct msqid_ds ds;
+  int id;
+
+  id = msg_test_create(IPC_PRIVATE, 0640);
+  assert_true(id >= 0);
+
+  memset(&ds, 0xff, sizeof(ds));
+  assert_int_equal(msgctl(id, IPC_STAT, &ds), 0);
+  assert_int_equal(ds.msg_perm.mode & 0777, 0640);
+  assert_int_equal(ds.msg_lspid, 0);
+  assert_int_equal(ds.msg_lrpid, 0);
+  assert_int_equal(ds.msg_stime, 0);
+  assert_int_equal(ds.msg_rtime, 0);
+  assert_true(ds.msg_ctime > 0);
+
+  assert_int_equal(msg_test_send(id, 1, "a", 1, 0), 0);
+  memset(&ds, 0xff, sizeof(ds));
+  assert_int_equal(msgctl(id, IPC_STAT, &ds), 0);
+  assert_int_equal(ds.msg_lspid, getpid());
+  assert_true(ds.msg_stime > 0);
+
+  assert_int_equal(msg_test_recv(id, &buf, 1, 0, 0), 1);
+  memset(&ds, 0xff, sizeof(ds));
+  assert_int_equal(msgctl(id, IPC_STAT, &ds), 0);
+  assert_int_equal(ds.msg_lrpid, getpid());
+  assert_true(ds.msg_rtime > 0);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_ctl_set
+ *
+ * Description:
+ *   IPC_SET changes msg_qbytes, and IPC_STAT gives the new value.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_ctl_set(FAR void **state)
+{
+  struct msqid_ds ds;
+  int id;
+
+  id = msg_test_create(IPC_PRIVATE, 0600);
+  assert_true(id >= 0);
+
+  assert_int_equal(msg_test_set_qbytes(id, 3 * MSG_TEST_MAXSIZE), 0);
+  memset(&ds, 0, sizeof(ds));
+  assert_int_equal(msgctl(id, IPC_STAT, &ds), 0);
+  assert_int_equal(ds.msg_qbytes, 3 * MSG_TEST_MAXSIZE);
+
+  assert_int_equal(msg_test_set_qbytes(id, MSG_TEST_MAXSIZE + 1), 0);
+  memset(&ds, 0, sizeof(ds));
+  assert_int_equal(msgctl(id, IPC_STAT, &ds), 0);
+  assert_int_equal(ds.msg_qbytes, MSG_TEST_MAXSIZE + 1);
+
+  assert_int_equal(msgctl(id, IPC_SET, NULL), -1);
+  assert_int_equal(errno, EFAULT);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_ctl_rmid
+ *
+ * Description:
+ *   IPC_RMID removes the queue and its messages; the identifier is then
+ *   not valid.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_ctl_rmid(FAR void **state)
+{
+  struct msg_test_buf_s buf;
+  struct msqid_ds ds;
+  int id;
+
+  id = msg_test_create(IPC_PRIVATE, 0600);
+  assert_true(id >= 0);
+
+  assert_int_equal(msg_test_send(id, 1, "a", 1, 0), 0);
+  assert_int_equal(msg_test_remove(id), 0);
+
+  assert_int_equal(msgctl(id, IPC_STAT, &ds), -1);
+  assert_int_equal(errno, EINVAL);
+  assert_int_equal(msgctl(id, IPC_RMID, NULL), -1);
+  assert_int_equal(errno, EINVAL);
+  assert_int_equal(msg_test_send(id, 1, "a", 1, IPC_NOWAIT), -1);
+  assert_int_equal(errno, EINVAL);
+  assert_int_equal(msg_test_recv(id, &buf, 1, 0, IPC_NOWAIT), -1);
+  assert_int_equal(errno, EINVAL);
+}
diff --git a/testing/testsuites/kernel/msg/cases/msg_test_get.c 
b/testing/testsuites/kernel/msg/cases/msg_test_get.c
new file mode 100644
index 000000000..ef9fca853
--- /dev/null
+++ b/testing/testsuites/kernel/msg/cases/msg_test_get.c
@@ -0,0 +1,152 @@
+/****************************************************************************
+ * apps/testing/testsuites/kernel/msg/cases/msg_test_get.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+
+#include "MsgTest.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: test_nuttx_msg_get_private
+ *
+ * Description:
+ *   IPC_PRIVATE always creates a new queue, also without IPC_CREAT.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_get_private(FAR void **state)
+{
+  struct msqid_ds ds;
+  int id1;
+  int id2;
+
+  id1 = msg_test_create(IPC_PRIVATE, IPC_CREAT | 0600);
+  assert_true(id1 >= 0);
+
+  id2 = msg_test_create(IPC_PRIVATE, 0600);
+  assert_true(id2 >= 0);
+  assert_int_not_equal(id1, id2);
+
+  assert_int_equal(msg_test_remove(id1), 0);
+  assert_int_equal(msgctl(id1, IPC_STAT, &ds), -1);
+  assert_int_equal(errno, EINVAL);
+  assert_int_equal(msg_test_qnum(id2), 0);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_get_key
+ *
+ * Description:
+ *   msgget() of a key: ENOENT before IPC_CREAT, then the same identifier,
+ *   and EEXIST with IPC_CREAT | IPC_EXCL.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_get_key(FAR void **state)
+{
+  int id;
+
+  assert_int_equal(msgget(MSG_TEST_KEY, 0600), -1);
+  assert_int_equal(errno, ENOENT);
+
+  id = msg_test_create(MSG_TEST_KEY, IPC_CREAT | 0600);
+  assert_true(id >= 0);
+
+  assert_int_equal(msgget(MSG_TEST_KEY, 0600), id);
+  assert_int_equal(msg_test_create(MSG_TEST_KEY, IPC_CREAT | 0600), id);
+
+  assert_int_equal(msg_test_create(MSG_TEST_KEY,
+                                   IPC_CREAT | IPC_EXCL | 0600), -1);
+  assert_int_equal(errno, EEXIST);
+
+  assert_int_equal(msg_test_remove(id), 0);
+  assert_int_equal(msgget(MSG_TEST_KEY, 0600), -1);
+  assert_int_equal(errno, ENOENT);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_get_many
+ *
+ * Description:
+ *   More than 250 queues at the same time: each one has its own
+ *   identifier, and msgctl() finds each one.  Skipped when the kernel heap
+ *   is too small for them.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_get_many(FAR void **state)
+{
+  static int ids[MSG_TEST_NMANY];
+  struct msqid_ds ds;
+  int nfound = 0;
+  int ndup = 0;
+  int n;
+  int i;
+  int j;
+
+  for (n = 0; n < MSG_TEST_NMANY; n++)
+    {
+      ids[n] = msgget(IPC_PRIVATE, 0600);
+      if (ids[n] < 0)
+        {
+          break;
+        }
+    }
+
+  for (i = 0; i < n; i++)
+    {
+      if (msgctl(ids[i], IPC_STAT, &ds) == 0)
+        {
+          nfound++;
+        }
+
+      for (j = 0; j < i; j++)
+        {
+          if (ids[j] == ids[i])
+            {
+              ndup++;
+            }
+        }
+    }
+
+  for (i = 0; i < n; i++)
+    {
+      msgctl(ids[i], IPC_RMID, NULL);
+    }
+
+  if (n < MSG_TEST_NMANY)
+    {
+      skip();
+    }
+
+  assert_int_equal(nfound, MSG_TEST_NMANY);
+  assert_int_equal(ndup, 0);
+}
diff --git a/testing/testsuites/kernel/msg/cases/msg_test_pool.c 
b/testing/testsuites/kernel/msg/cases/msg_test_pool.c
new file mode 100644
index 000000000..29d31beca
--- /dev/null
+++ b/testing/testsuites/kernel/msg/cases/msg_test_pool.c
@@ -0,0 +1,186 @@
+/****************************************************************************
+ * apps/testing/testsuites/kernel/msg/cases/msg_test_pool.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+
+#include "MsgTest.h"
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct msg_test_waiter_s g_msg_test_poolwaiter;
+static volatile int g_msg_test_poolsig;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static void msg_test_poolhandler(int signo)
+{
+  g_msg_test_poolsig++;
+}
+
+/* Take all CONFIG_PREALLOC_MQ_MSGS messages of the system-wide pool: they
+ * stay in the queue *full.  Return the identifier of a second, empty queue.
+ */
+
+static int msg_test_fill_pool(FAR int *full)
+{
+  int id;
+  int i;
+
+  *full = msg_test_create(IPC_PRIVATE, 0600);
+  assert_true(*full >= 0);
+  assert_int_equal(msg_test_set_qbytes(*full, CONFIG_PREALLOC_MQ_MSGS *
+                                              MSG_TEST_MAXSIZE), 0);
+
+  for (i = 0; i < CONFIG_PREALLOC_MQ_MSGS; i++)
+    {
+      assert_int_equal(msg_test_send(*full, 1, "p", 1, IPC_NOWAIT), 0);
+    }
+
+  id = msg_test_create(IPC_PRIVATE, 0600);
+  assert_true(id >= 0);
+  return id;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: test_nuttx_msg_pool_nowait
+ *
+ * Description:
+ *   No free message in the system: msgsnd() with IPC_NOWAIT gives EAGAIN.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_pool_nowait(FAR void **state)
+{
+  int full;
+  int id;
+
+  id = msg_test_fill_pool(&full);
+  assert_int_equal(msg_test_send(id, 1, "a", 1, IPC_NOWAIT), -1);
+  assert_int_equal(errno, EAGAIN);
+  assert_int_equal(msg_test_qnum(id), 0);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_pool_wait
+ *
+ * Description:
+ *   No free message in the system: msgsnd() blocks until msgrcv() of
+ *   another queue frees a message.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_pool_wait(FAR void **state)
+{
+  FAR struct msg_test_waiter_s *w = &g_msg_test_poolwaiter;
+  struct msg_test_buf_s buf;
+  int full;
+  int id;
+
+  id = msg_test_fill_pool(&full);
+  assert_int_equal(msg_test_qnum(full), CONFIG_PREALLOC_MQ_MSGS);
+
+  msg_test_start(w, id, true, 1);
+  assert_false(w->done);
+
+  assert_int_equal(msg_test_recv(full, &buf, 1, 0, 0), 1);
+  assert_true(msg_test_finish(w));
+  assert_int_equal(w->ret, 0);
+  assert_int_equal(msg_test_qnum(id), 1);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_pool_eintr
+ *
+ * Description:
+ *   A signal interrupts a thread that waits in msgsnd() for a free
+ *   message: EINTR.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_pool_eintr(FAR void **state)
+{
+  FAR struct msg_test_waiter_s *w = &g_msg_test_poolwaiter;
+  struct sigaction act;
+  struct sigaction old;
+  int full;
+  int id;
+
+  memset(&act, 0, sizeof(act));
+  act.sa_handler = msg_test_poolhandler;
+  sigemptyset(&act.sa_mask);
+  assert_int_equal(sigaction(SIGUSR1, &act, &old), 0);
+
+  id = msg_test_fill_pool(&full);
+  g_msg_test_poolsig = 0;
+  msg_test_start(w, id, true, 1);
+  assert_false(w->done);
+
+  assert_int_equal(pthread_kill(w->thread, SIGUSR1), 0);
+  assert_true(msg_test_finish(w));
+  sigaction(SIGUSR1, &old, NULL);
+
+  assert_int_equal(g_msg_test_poolsig, 1);
+  assert_int_equal(w->ret, -1);
+  assert_int_equal(w->err, EINTR);
+  assert_int_equal(msg_test_qnum(id), 0);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_pool_eidrm
+ *
+ * Description:
+ *   IPC_RMID of the queue of a thread that waits in msgsnd() for a free
+ *   message: EIDRM, while the pool stays empty.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_pool_eidrm(FAR void **state)
+{
+  FAR struct msg_test_waiter_s *w = &g_msg_test_poolwaiter;
+  int full;
+  int id;
+
+  id = msg_test_fill_pool(&full);
+  msg_test_start(w, id, true, 1);
+  assert_false(w->done);
+
+  assert_int_equal(msg_test_remove(id), 0);
+  assert_true(msg_test_finish(w));
+  assert_int_equal(w->ret, -1);
+  assert_int_equal(w->err, EIDRM);
+}
diff --git a/testing/testsuites/kernel/msg/cases/msg_test_size.c 
b/testing/testsuites/kernel/msg/cases/msg_test_size.c
new file mode 100644
index 000000000..7ba8d5e2a
--- /dev/null
+++ b/testing/testsuites/kernel/msg/cases/msg_test_size.c
@@ -0,0 +1,161 @@
+/****************************************************************************
+ * apps/testing/testsuites/kernel/msg/cases/msg_test_size.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include "MsgTest.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: test_nuttx_msg_noerror
+ *
+ * Description:
+ *   MSG_NOERROR truncates a message that is longer than msgsz.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_noerror(FAR void **state)
+{
+  struct msg_test_buf_s buf;
+  int id;
+
+  id = msg_test_create(IPC_PRIVATE, 0600);
+  assert_true(id >= 0);
+
+  assert_int_equal(msg_test_send(id, 1, "abcdefgh", 8, 0), 0);
+  assert_int_equal(msg_test_recv(id, &buf, 4, 0, MSG_NOERROR), 4);
+  assert_int_equal(buf.mtype, 1);
+  assert_memory_equal(buf.mtext, "abcd", 4);
+  assert_int_equal(buf.mtext[4], 0);
+  assert_int_equal(msg_test_qnum(id), 0);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_e2big
+ *
+ * Description:
+ *   Without MSG_NOERROR, a message longer than msgsz gives E2BIG and stays
+ *   in the queue.  A message that fits is received, also with a small
+ *   msgsz.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_e2big(FAR void **state)
+{
+  struct msg_test_buf_s buf;
+  int id;
+
+  id = msg_test_create(IPC_PRIVATE, 0600);
+  assert_true(id >= 0);
+
+  assert_int_equal(msg_test_send(id, 1, "abcdefgh", 8, 0), 0);
+
+  assert_int_equal(msg_test_recv(id, &buf, 4, 0, 0), -1);
+  assert_int_equal(errno, E2BIG);
+  assert_int_equal(msg_test_recv(id, &buf, 7, 0, IPC_NOWAIT), -1);
+  assert_int_equal(errno, E2BIG);
+  assert_int_equal(msg_test_qnum(id), 1);
+
+  assert_int_equal(msg_test_recv(id, &buf, 8, 0, 0), 8);
+  assert_memory_equal(buf.mtext, "abcdefgh", 8);
+
+  assert_int_equal(msg_test_send(id, 1, "ab", 2, 0), 0);
+  assert_int_equal(msg_test_recv(id, &buf, 2, 0, 0), 2);
+  assert_memory_equal(buf.mtext, "ab", 2);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_nowait
+ *
+ * Description:
+ *   IPC_NOWAIT: msgrcv() of an empty queue gives ENOMSG, and msgsnd() to a
+ *   full queue gives EAGAIN.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_nowait(FAR void **state)
+{
+  char text[MSG_TEST_MAXSIZE];
+  struct msg_test_buf_s buf;
+  int id;
+
+  id = msg_test_create(IPC_PRIVATE, 0600);
+  assert_true(id >= 0);
+
+  assert_int_equal(msg_test_recv(id, &buf, MSG_TEST_MAXSIZE, 0,
+                                 IPC_NOWAIT), -1);
+  assert_int_equal(errno, ENOMSG);
+
+  /* Room for two messages of the maximum size */
+
+  assert_int_equal(msg_test_set_qbytes(id, 2 * MSG_TEST_MAXSIZE), 0);
+
+  memset(text, 'x', sizeof(text));
+  assert_int_equal(msg_test_send(id, 1, text, sizeof(text), IPC_NOWAIT), 0);
+  assert_int_equal(msg_test_send(id, 1, text, sizeof(text), IPC_NOWAIT), 0);
+  assert_int_equal(msg_test_send(id, 1, text, sizeof(text), IPC_NOWAIT), -1);
+  assert_int_equal(errno, EAGAIN);
+  assert_int_equal(msg_test_qnum(id), 2);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_einval
+ *
+ * Description:
+ *   EINVAL: a type less than 1, a message that is too long, and a queue
+ *   identifier that is not valid.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_einval(FAR void **state)
+{
+  char text[MSG_TEST_MAXSIZE + 1];
+  struct msg_test_buf_s buf;
+  int id;
+
+  id = msg_test_create(IPC_PRIVATE, 0600);
+  assert_true(id >= 0);
+
+  assert_int_equal(msg_test_send(id, 0, "a", 1, IPC_NOWAIT), -1);
+  assert_int_equal(errno, EINVAL);
+  assert_int_equal(msg_test_send(id, -1, "a", 1, IPC_NOWAIT), -1);
+  assert_int_equal(errno, EINVAL);
+  memset(text, 'x', sizeof(text));
+  assert_int_equal(msg_test_send(id, 1, text, sizeof(text), IPC_NOWAIT), -1);
+  assert_int_equal(errno, EINVAL);
+  assert_int_equal(msg_test_qnum(id), 0);
+
+  assert_int_equal(msg_test_send(-1, 1, "a", 1, IPC_NOWAIT), -1);
+  assert_int_equal(errno, EINVAL);
+  assert_int_equal(msg_test_recv(-1, &buf, 1, 0, IPC_NOWAIT), -1);
+  assert_int_equal(errno, EINVAL);
+}
diff --git a/testing/testsuites/kernel/msg/cases/msg_test_type.c 
b/testing/testsuites/kernel/msg/cases/msg_test_type.c
new file mode 100644
index 000000000..f23ab4c14
--- /dev/null
+++ b/testing/testsuites/kernel/msg/cases/msg_test_type.c
@@ -0,0 +1,141 @@
+/****************************************************************************
+ * apps/testing/testsuites/kernel/msg/cases/msg_test_type.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+
+#include "MsgTest.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/* Receive one message and check its type and its one-byte text */
+
+static void msg_test_expect(int msqid, long msgtyp, long mtype, char text)
+{
+  struct msg_test_buf_s buf;
+
+  assert_int_equal(msg_test_recv(msqid, &buf, MSG_TEST_MAXSIZE, msgtyp,
+                                 IPC_NOWAIT), 1);
+  assert_int_equal(buf.mtype, mtype);
+  assert_int_equal(buf.mtext[0], text);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: test_nuttx_msg_type_zero
+ *
+ * Description:
+ *   msgtyp 0 receives the messages in the order of msgsnd().
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_type_zero(FAR void **state)
+{
+  int id;
+
+  id = msg_test_create(IPC_PRIVATE, 0600);
+  assert_true(id >= 0);
+
+  assert_int_equal(msg_test_send(id, 3, "a", 1, 0), 0);
+  assert_int_equal(msg_test_send(id, 1, "b", 1, 0), 0);
+  assert_int_equal(msg_test_send(id, 2, "c", 1, 0), 0);
+  assert_int_equal(msg_test_qnum(id), 3);
+
+  msg_test_expect(id, 0, 3, 'a');
+  msg_test_expect(id, 0, 1, 'b');
+  msg_test_expect(id, 0, 2, 'c');
+  assert_int_equal(msg_test_qnum(id), 0);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_type_positive
+ *
+ * Description:
+ *   msgtyp > 0 receives the first message of that type.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_type_positive(FAR void **state)
+{
+  struct msg_test_buf_s buf;
+  int id;
+
+  id = msg_test_create(IPC_PRIVATE, 0600);
+  assert_true(id >= 0);
+
+  assert_int_equal(msg_test_send(id, 1, "a", 1, 0), 0);
+  assert_int_equal(msg_test_send(id, 2, "b", 1, 0), 0);
+  assert_int_equal(msg_test_send(id, 1, "c", 1, 0), 0);
+
+  msg_test_expect(id, 2, 2, 'b');
+  msg_test_expect(id, 1, 1, 'a');
+  msg_test_expect(id, 1, 1, 'c');
+
+  assert_int_equal(msg_test_recv(id, &buf, MSG_TEST_MAXSIZE, 1,
+                                 IPC_NOWAIT), -1);
+  assert_int_equal(errno, ENOMSG);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_type_negative
+ *
+ * Description:
+ *   msgtyp < 0 receives the first message of the lowest type that is less
+ *   than or equal to the absolute value of msgtyp.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_type_negative(FAR void **state)
+{
+  struct msg_test_buf_s buf;
+  int id;
+
+  id = msg_test_create(IPC_PRIVATE, 0600);
+  assert_true(id >= 0);
+
+  assert_int_equal(msg_test_send(id, 3, "a", 1, 0), 0);
+  assert_int_equal(msg_test_send(id, 2, "b", 1, 0), 0);
+  assert_int_equal(msg_test_send(id, 1, "c", 1, 0), 0);
+  assert_int_equal(msg_test_send(id, 1, "d", 1, 0), 0);
+
+  msg_test_expect(id, -2, 1, 'c');
+  msg_test_expect(id, -2, 1, 'd');
+  msg_test_expect(id, -2, 2, 'b');
+
+  /* Only type 3 is left: no message of type 2 or less */
+
+  assert_int_equal(msg_test_recv(id, &buf, MSG_TEST_MAXSIZE, -2,
+                                 IPC_NOWAIT), -1);
+  assert_int_equal(errno, ENOMSG);
+
+  msg_test_expect(id, -3, 3, 'a');
+}
diff --git a/testing/testsuites/kernel/msg/cases/msg_test_wait.c 
b/testing/testsuites/kernel/msg/cases/msg_test_wait.c
new file mode 100644
index 000000000..c5acd45fc
--- /dev/null
+++ b/testing/testsuites/kernel/msg/cases/msg_test_wait.c
@@ -0,0 +1,275 @@
+/****************************************************************************
+ * apps/testing/testsuites/kernel/msg/cases/msg_test_wait.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "MsgTest.h"
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct msg_test_waiter_s g_msg_test_waiter;
+static struct msg_test_waiter_s g_msg_test_waiter2;
+static volatile int g_msg_test_nsig;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static void msg_test_sighandler(int signo)
+{
+  g_msg_test_nsig++;
+}
+
+/* A new queue with room for one message of the maximum size; full is true:
+ * the queue has one message of type 1.
+ */
+
+static int msg_test_queue(bool full)
+{
+  char text[MSG_TEST_MAXSIZE];
+  int id;
+
+  id = msg_test_create(IPC_PRIVATE, 0600);
+  assert_true(id >= 0);
+  assert_int_equal(msg_test_set_qbytes(id, MSG_TEST_MAXSIZE), 0);
+
+  if (full)
+    {
+      memset(text, 'x', sizeof(text));
+      assert_int_equal(msg_test_send(id, 1, text, sizeof(text),
+                                     IPC_NOWAIT), 0);
+      assert_int_equal(msg_test_send(id, 1, text, sizeof(text),
+                                     IPC_NOWAIT), -1);
+      assert_int_equal(errno, EAGAIN);
+    }
+
+  return id;
+}
+
+/* A signal to a thread blocked in msgsnd() or msgrcv(): EINTR */
+
+static void msg_test_eintr(bool snd)
+{
+  FAR struct msg_test_waiter_s *w = &g_msg_test_waiter;
+  struct sigaction act;
+  struct sigaction old;
+  int id;
+
+  memset(&act, 0, sizeof(act));
+  act.sa_handler = msg_test_sighandler;
+  sigemptyset(&act.sa_mask);
+  assert_int_equal(sigaction(SIGUSR1, &act, &old), 0);
+
+  id = msg_test_queue(snd);
+  g_msg_test_nsig = 0;
+  msg_test_start(w, id, snd, 1);
+  assert_false(w->done);
+
+  assert_int_equal(pthread_kill(w->thread, SIGUSR1), 0);
+  assert_true(msg_test_finish(w));
+  sigaction(SIGUSR1, &old, NULL);
+
+  assert_int_equal(g_msg_test_nsig, 1);
+  assert_int_equal(w->ret, -1);
+  assert_int_equal(w->err, EINTR);
+  assert_int_equal(msg_test_qnum(id), snd ? 1 : 0);
+}
+
+/* IPC_RMID of the queue of a thread blocked in msgsnd() or msgrcv() */
+
+static void msg_test_eidrm(bool snd)
+{
+  FAR struct msg_test_waiter_s *w = &g_msg_test_waiter;
+  int id;
+
+  id = msg_test_queue(snd);
+  msg_test_start(w, id, snd, 1);
+  assert_false(w->done);
+
+  assert_int_equal(msg_test_remove(id), 0);
+  assert_true(msg_test_finish(w));
+  assert_int_equal(w->ret, -1);
+  assert_int_equal(w->err, EIDRM);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: test_nuttx_msg_wait_rcv
+ *
+ * Description:
+ *   A thread blocked in msgrcv() of type 2 stays blocked after a message of
+ *   type 1, and receives the next message of type 2.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_wait_rcv(FAR void **state)
+{
+  FAR struct msg_test_waiter_s *w = &g_msg_test_waiter;
+  int id;
+
+  id = msg_test_queue(false);
+  assert_int_equal(msg_test_set_qbytes(id, 2 * MSG_TEST_MAXSIZE), 0);
+  msg_test_start(w, id, false, 2);
+  assert_false(w->done);
+
+  assert_int_equal(msg_test_send(id, 1, "a", 1, 0), 0);
+  usleep(100000);
+  assert_false(w->done);
+
+  assert_int_equal(msg_test_send(id, 2, "b", 1, 0), 0);
+  assert_true(msg_test_finish(w));
+  assert_int_equal(w->ret, 1);
+  assert_int_equal(w->buf.mtype, 2);
+  assert_int_equal(w->buf.mtext[0], 'b');
+  assert_int_equal(msg_test_qnum(id), 1);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_wait_types
+ *
+ * Description:
+ *   Two threads block in msgrcv(): the first for type 2, the second for
+ *   type 1.  A message of type 1 goes to the second thread.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_wait_types(FAR void **state)
+{
+  FAR struct msg_test_waiter_s *w1 = &g_msg_test_waiter;
+  FAR struct msg_test_waiter_s *w2 = &g_msg_test_waiter2;
+  int id;
+
+  id = msg_test_queue(false);
+  assert_int_equal(msg_test_set_qbytes(id, 2 * MSG_TEST_MAXSIZE), 0);
+  msg_test_start(w1, id, false, 2);
+  msg_test_start(w2, id, false, 1);
+  assert_false(w1->done);
+  assert_false(w2->done);
+
+  assert_int_equal(msg_test_send(id, 1, "a", 1, 0), 0);
+  assert_true(msg_test_finish(w2));
+  assert_int_equal(w2->ret, 1);
+  assert_int_equal(w2->buf.mtype, 1);
+  assert_false(w1->done);
+
+  assert_int_equal(msg_test_send(id, 2, "b", 1, 0), 0);
+  assert_true(msg_test_finish(w1));
+  assert_int_equal(w1->ret, 1);
+  assert_int_equal(w1->buf.mtype, 2);
+  assert_int_equal(msg_test_qnum(id), 0);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_wait_snd
+ *
+ * Description:
+ *   A thread blocked in msgsnd() of a full queue sends its message after
+ *   msgrcv() makes room.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_wait_snd(FAR void **state)
+{
+  FAR struct msg_test_waiter_s *w = &g_msg_test_waiter;
+  struct msg_test_buf_s buf;
+  int id;
+
+  id = msg_test_queue(true);
+  msg_test_start(w, id, true, 2);
+  assert_false(w->done);
+
+  assert_int_equal(msg_test_recv(id, &buf, MSG_TEST_MAXSIZE, 0, 0),
+                   MSG_TEST_MAXSIZE);
+  assert_int_equal(buf.mtype, 1);
+  assert_true(msg_test_finish(w));
+  assert_int_equal(w->ret, 0);
+
+  assert_int_equal(msg_test_recv(id, &buf, MSG_TEST_MAXSIZE, 0,
+                                 IPC_NOWAIT), MSG_TEST_MAXSIZE);
+  assert_int_equal(buf.mtype, 2);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_eidrm_rcv
+ *
+ * Description:
+ *   IPC_RMID wakes up a thread blocked in msgrcv(): EIDRM.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_eidrm_rcv(FAR void **state)
+{
+  msg_test_eidrm(false);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_eidrm_snd
+ *
+ * Description:
+ *   IPC_RMID wakes up a thread blocked in msgsnd(): EIDRM.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_eidrm_snd(FAR void **state)
+{
+  msg_test_eidrm(true);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_eintr_rcv
+ *
+ * Description:
+ *   A signal interrupts a thread blocked in msgrcv(): EINTR.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_eintr_rcv(FAR void **state)
+{
+  msg_test_eintr(false);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_eintr_snd
+ *
+ * Description:
+ *   A signal interrupts a thread blocked in msgsnd(): EINTR.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_eintr_snd(FAR void **state)
+{
+  msg_test_eintr(true);
+}
diff --git a/testing/testsuites/kernel/msg/cmocka_msg_test.c 
b/testing/testsuites/kernel/msg/cmocka_msg_test.c
new file mode 100644
index 000000000..93cc60062
--- /dev/null
+++ b/testing/testsuites/kernel/msg/cmocka_msg_test.c
@@ -0,0 +1,77 @@
+/****************************************************************************
+ * apps/testing/testsuites/kernel/msg/cmocka_msg_test.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "MsgTest.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define MSG_TEST(f) cmocka_unit_test_setup_teardown(f, NULL, msg_test_teardown)
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: main
+ ****************************************************************************/
+
+int main(int argc, FAR char *argv[])
+{
+  const struct CMUnitTest nuttx_msg_test_suites[] =
+  {
+    MSG_TEST(test_nuttx_msg_get_private),
+    MSG_TEST(test_nuttx_msg_get_key),
+    MSG_TEST(test_nuttx_msg_type_zero),
+    MSG_TEST(test_nuttx_msg_type_positive),
+    MSG_TEST(test_nuttx_msg_type_negative),
+    MSG_TEST(test_nuttx_msg_noerror),
+    MSG_TEST(test_nuttx_msg_e2big),
+    MSG_TEST(test_nuttx_msg_nowait),
+    MSG_TEST(test_nuttx_msg_einval),
+    MSG_TEST(test_nuttx_msg_ctl_stat),
+    MSG_TEST(test_nuttx_msg_ctl_fields),
+    MSG_TEST(test_nuttx_msg_ctl_set),
+    MSG_TEST(test_nuttx_msg_ctl_rmid),
+    MSG_TEST(test_nuttx_msg_wait_rcv),
+    MSG_TEST(test_nuttx_msg_wait_types),
+    MSG_TEST(test_nuttx_msg_wait_snd),
+    MSG_TEST(test_nuttx_msg_eidrm_rcv),
+    MSG_TEST(test_nuttx_msg_eidrm_snd),
+    MSG_TEST(test_nuttx_msg_eintr_rcv),
+    MSG_TEST(test_nuttx_msg_eintr_snd),
+    MSG_TEST(test_nuttx_msg_pool_nowait),
+    MSG_TEST(test_nuttx_msg_pool_wait),
+    MSG_TEST(test_nuttx_msg_pool_eintr),
+    MSG_TEST(test_nuttx_msg_pool_eidrm),
+    MSG_TEST(test_nuttx_msg_get_many),
+  };
+
+  return cmocka_run_group_tests(nuttx_msg_test_suites, NULL, NULL);
+}
diff --git a/testing/testsuites/kernel/msg/common/test_msg_common.c 
b/testing/testsuites/kernel/msg/common/test_msg_common.c
new file mode 100644
index 000000000..51de9121b
--- /dev/null
+++ b/testing/testsuites/kernel/msg/common/test_msg_common.c
@@ -0,0 +1,240 @@
+/****************************************************************************
+ * apps/testing/testsuites/kernel/msg/common/test_msg_common.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <sched.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "MsgTest.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define MSG_TEST_NQUEUES  8
+#define MSG_TEST_NWAITERS 4
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int g_msg_test_ids[MSG_TEST_NQUEUES];
+static int g_msg_test_nids;
+static FAR struct msg_test_waiter_s *g_msg_test_waiters[MSG_TEST_NWAITERS];
+static int g_msg_test_nwaiters;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static FAR void *msg_test_waiter(FAR void *arg)
+{
+  FAR struct msg_test_waiter_s *w = arg;
+
+  errno = 0;
+  if (w->snd)
+    {
+      w->buf.mtype = w->mtype;
+      w->ret = msgsnd(w->msqid, &w->buf, MSG_TEST_MAXSIZE, 0);
+    }
+  else
+    {
+      w->ret = msgrcv(w->msqid, &w->buf, MSG_TEST_MAXSIZE, w->mtype, 0);
+    }
+
+  w->err  = w->ret < 0 ? errno : 0;
+  w->done = true;
+  return NULL;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/* msgget() that remembers the queue, so that the teardown removes it */
+
+int msg_test_create(key_t key, int msgflg)
+{
+  int msqid;
+
+  msqid = msgget(key, msgflg);
+  if (msqid >= 0 && g_msg_test_nids < MSG_TEST_NQUEUES)
+    {
+      g_msg_test_ids[g_msg_test_nids++] = msqid;
+    }
+
+  return msqid;
+}
+
+int msg_test_remove(int msqid)
+{
+  int i;
+
+  for (i = 0; i < g_msg_test_nids; i++)
+    {
+      if (g_msg_test_ids[i] == msqid)
+        {
+          g_msg_test_ids[i] = g_msg_test_ids[--g_msg_test_nids];
+          break;
+        }
+    }
+
+  return msgctl(msqid, IPC_RMID, NULL);
+}
+
+int msg_test_send(int msqid, long mtype, FAR const char *text, size_t len,
+                  int msgflg)
+{
+  struct msg_test_buf_s buf;
+
+  memset(&buf, 0, sizeof(buf));
+  buf.mtype = mtype;
+  memcpy(buf.mtext, text, len);
+  return msgsnd(msqid, &buf, len, msgflg);
+}
+
+ssize_t msg_test_recv(int msqid, FAR struct msg_test_buf_s *buf,
+                      size_t len, long mtype, int msgflg)
+{
+  memset(buf, 0, sizeof(*buf));
+  return msgrcv(msqid, buf, len, mtype, msgflg);
+}
+
+long msg_test_qnum(int msqid)
+{
+  struct msqid_ds ds;
+
+  memset(&ds, 0, sizeof(ds));
+  if (msgctl(msqid, IPC_STAT, &ds) < 0)
+    {
+      return -1;
+    }
+
+  return ds.msg_qnum;
+}
+
+int msg_test_set_qbytes(int msqid, size_t qbytes)
+{
+  struct msqid_ds ds;
+  int ret;
+
+  memset(&ds, 0, sizeof(ds));
+  ret = msgctl(msqid, IPC_STAT, &ds);
+  if (ret == 0)
+    {
+      ds.msg_qbytes = qbytes;
+      ret = msgctl(msqid, IPC_SET, &ds);
+    }
+
+  return ret;
+}
+
+/* Start a thread with a higher priority than the caller that blocks in
+ * msgsnd() (snd true) or msgrcv() of msqid, and give it time to block.
+ */
+
+void msg_test_start(FAR struct msg_test_waiter_s *w, int msqid, bool snd,
+                    long mtype)
+{
+  struct sched_param param;
+  pthread_attr_t attr;
+  int policy;
+  int ret;
+
+  memset(w, 0, sizeof(*w));
+  w->msqid = msqid;
+  w->snd   = snd;
+  w->mtype = mtype;
+  w->ret   = -2;
+
+  ret = pthread_getschedparam(pthread_self(), &policy, &param);
+  assert_int_equal(ret, 0);
+  if (param.sched_priority < sched_get_priority_max(SCHED_FIFO))
+    {
+      param.sched_priority++;
+    }
+
+  pthread_attr_init(&attr);
+  pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
+  pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
+  pthread_attr_setschedparam(&attr, &param);
+  ret = pthread_create(&w->thread, &attr, msg_test_waiter, w);
+  pthread_attr_destroy(&attr);
+  assert_int_equal(ret, 0);
+
+  if (g_msg_test_nwaiters < MSG_TEST_NWAITERS)
+    {
+      g_msg_test_waiters[g_msg_test_nwaiters++] = w;
+    }
+
+  usleep(100000);
+}
+
+/* Wait up to 3 seconds for the waiter to return and join it; false if it
+ * is still blocked.
+ */
+
+bool msg_test_finish(FAR struct msg_test_waiter_s *w)
+{
+  int i;
+
+  for (i = 0; i < 300 && !w->done; i++)
+    {
+      usleep(10000);
+    }
+
+  if (w->done && !w->joined)
+    {
+      pthread_join(w->thread, NULL);
+      w->joined = true;
+    }
+
+  return w->done;
+}
+
+/* Remove the queues of the test case; this also wakes up its waiters */
+
+int msg_test_teardown(FAR void **state)
+{
+  int i;
+
+  while (g_msg_test_nids > 0)
+    {
+      msg_test_remove(g_msg_test_ids[0]);
+    }
+
+  for (i = 0; i < g_msg_test_nwaiters; i++)
+    {
+      msg_test_finish(g_msg_test_waiters[i]);
+    }
+
+  g_msg_test_nwaiters = 0;
+  return 0;
+}
diff --git a/testing/testsuites/kernel/msg/include/MsgTest.h 
b/testing/testsuites/kernel/msg/include/MsgTest.h
new file mode 100644
index 000000000..e99673333
--- /dev/null
+++ b/testing/testsuites/kernel/msg/include/MsgTest.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+ * apps/testing/testsuites/kernel/msg/include/MsgTest.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_TESTING_TESTSUITES_KERNEL_MSG_INCLUDE_MSGTEST_H
+#define __APPS_TESTING_TESTSUITES_KERNEL_MSG_INCLUDE_MSGTEST_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* The largest message that msgsnd() accepts */
+
+#define MSG_TEST_MAXSIZE   CONFIG_MQ_MAXMSGSIZE
+
+/* The key of the queue in the msgget() test */
+
+#define MSG_TEST_KEY       ((key_t)0x4d534754)
+
+/* The number of queues in the test of many queues */
+
+#define MSG_TEST_NMANY     260
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct msg_test_buf_s
+{
+  long mtype;
+  char mtext[MSG_TEST_MAXSIZE + 1];
+};
+
+/* A thread that blocks in msgsnd() or msgrcv() */
+
+struct msg_test_waiter_s
+{
+  pthread_t thread;
+  int msqid;
+  bool snd;
+  long mtype;
+  volatile bool done;
+  bool joined;
+  ssize_t ret;
+  int err;
+  struct msg_test_buf_s buf;
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/* common/test_msg_common.c *************************************************/
+
+int msg_test_create(key_t key, int msgflg);
+int msg_test_remove(int msqid);
+int msg_test_send(int msqid, long mtype, FAR const char *text, size_t len,
+                  int msgflg);
+ssize_t msg_test_recv(int msqid, FAR struct msg_test_buf_s *buf,
+                      size_t len, long mtype, int msgflg);
+long msg_test_qnum(int msqid);
+int msg_test_set_qbytes(int msqid, size_t qbytes);
+void msg_test_start(FAR struct msg_test_waiter_s *w, int msqid, bool snd,
+                    long mtype);
+bool msg_test_finish(FAR struct msg_test_waiter_s *w);
+int msg_test_teardown(FAR void **state);
+
+/* cases/msg_test_get.c *****************************************************/
+
+void test_nuttx_msg_get_private(FAR void **state);
+void test_nuttx_msg_get_key(FAR void **state);
+void test_nuttx_msg_get_many(FAR void **state);
+
+/* cases/msg_test_type.c ****************************************************/
+
+void test_nuttx_msg_type_zero(FAR void **state);
+void test_nuttx_msg_type_positive(FAR void **state);
+void test_nuttx_msg_type_negative(FAR void **state);
+
+/* cases/msg_test_size.c ****************************************************/
+
+void test_nuttx_msg_noerror(FAR void **state);
+void test_nuttx_msg_e2big(FAR void **state);
+void test_nuttx_msg_nowait(FAR void **state);
+void test_nuttx_msg_einval(FAR void **state);
+
+/* cases/msg_test_ctl.c *****************************************************/
+
+void test_nuttx_msg_ctl_stat(FAR void **state);
+void test_nuttx_msg_ctl_fields(FAR void **state);
+void test_nuttx_msg_ctl_set(FAR void **state);
+void test_nuttx_msg_ctl_rmid(FAR void **state);
+
+/* cases/msg_test_wait.c ****************************************************/
+
+void test_nuttx_msg_wait_rcv(FAR void **state);
+void test_nuttx_msg_wait_types(FAR void **state);
+void test_nuttx_msg_wait_snd(FAR void **state);
+void test_nuttx_msg_eidrm_rcv(FAR void **state);
+void test_nuttx_msg_eidrm_snd(FAR void **state);
+void test_nuttx_msg_eintr_rcv(FAR void **state);
+void test_nuttx_msg_eintr_snd(FAR void **state);
+
+/* cases/msg_test_pool.c ****************************************************/
+
+void test_nuttx_msg_pool_nowait(FAR void **state);
+void test_nuttx_msg_pool_wait(FAR void **state);
+void test_nuttx_msg_pool_eintr(FAR void **state);
+void test_nuttx_msg_pool_eidrm(FAR void **state);
+
+#endif /* __APPS_TESTING_TESTSUITES_KERNEL_MSG_INCLUDE_MSGTEST_H */

Reply via email to