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

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

commit 6acf345296996c9fab13b2d0fd53721c2b7c910e
Author: Petro Karashchenko <[email protected]>
AuthorDate: Tue Apr 11 16:06:11 2023 +0300

    testing/ostest: add test case for task priority change with locked scheduler
    
    Signed-off-by: Petro Karashchenko <[email protected]>
---
 testing/ostest/CMakeLists.txt |  22 ++--
 testing/ostest/Makefile       |  13 +-
 testing/ostest/ostest.h       |   4 +
 testing/ostest/ostest_main.c  |   6 +
 testing/ostest/schedlock.c    | 274 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 296 insertions(+), 23 deletions(-)

diff --git a/testing/ostest/CMakeLists.txt b/testing/ostest/CMakeLists.txt
index b690b2e43..74f2f3f9b 100644
--- a/testing/ostest/CMakeLists.txt
+++ b/testing/ostest/CMakeLists.txt
@@ -20,13 +20,7 @@
 
 if(CONFIG_TESTING_OSTEST)
 
-  set(SRCS
-      getopt.c
-      restart.c
-      sigprocmask.c
-      sighand.c
-      signest.c
-      sighelper.c)
+  set(SRCS getopt.c restart.c sigprocmask.c sighand.c signest.c sighelper.c)
 
   if(CONFIG_DEV_NULL)
     list(APPEND SRCS dev_null.c)
@@ -71,8 +65,8 @@ if(CONFIG_TESTING_OSTEST)
       sem.c
       semtimed.c
       barrier.c)
-    list(APPEND SRCS timedwait.c)
-    list(APPEND SRCS pthread_rwlock.c pthread_rwlock_cancel.c)
+    list(APPEND SRCS timedwait.c pthread_rwlock.c pthread_rwlock_cancel.c
+         schedlock.c)
 
     if(CONFIG_SCHED_WAITPID)
       list(APPEND SRCS pthread_exit.c)
@@ -109,6 +103,10 @@ if(CONFIG_TESTING_OSTEST)
     if(CONFIG_SCHED_WORKQUEUE)
       list(APPEND SRCS wqueue.c)
     endif()
+
+    if(CONFIG_PRIORITY_INHERITANCE)
+      list(APPEND SRCS prioinherit.c)
+    endif() # CONFIG_PRIORITY_INHERITANCE
   endif() # CONFIG_DISABLE_PTHREAD
 
   if(NOT CONFIG_DISABLE_MQUEUE)
@@ -130,12 +128,6 @@ if(CONFIG_TESTING_OSTEST)
     endif()
   endif()
 
-  if(NOT CONFIG_DISABLE_PTHREAD)
-    if(CONFIG_PRIORITY_INHERITANCE)
-      list(APPEND SRCS prioinherit.c)
-    endif() # CONFIG_PRIORITY_INHERITANCE
-  endif() # CONFIG_DISABLE_PTHREAD
-
   if(CONFIG_ARCH_SETJMP_H)
     list(APPEND SRCS setjmp.c)
   endif()
diff --git a/testing/ostest/Makefile b/testing/ostest/Makefile
index 3bb70baff..fba321319 100644
--- a/testing/ostest/Makefile
+++ b/testing/ostest/Makefile
@@ -67,8 +67,7 @@ endif
 
 ifneq ($(CONFIG_DISABLE_PTHREAD),y)
 CSRCS += cancel.c cond.c mutex.c timedmutex.c sem.c semtimed.c barrier.c
-CSRCS += timedwait.c
-CSRCS += pthread_rwlock.c pthread_rwlock_cancel.c
+CSRCS += timedwait.c pthread_rwlock.c pthread_rwlock_cancel.c schedlock.c
 
 ifeq ($(CONFIG_SCHED_WAITPID),y)
 CSRCS += pthread_exit.c
@@ -105,6 +104,10 @@ endif
 ifeq ($(CONFIG_SCHED_WORKQUEUE),y)
 CSRCS += wqueue.c
 endif
+
+ifeq ($(CONFIG_PRIORITY_INHERITANCE),y)
+CSRCS += prioinherit.c
+endif
 endif # CONFIG_DISABLE_PTHREAD
 
 ifneq ($(CONFIG_DISABLE_MQUEUE),y)
@@ -126,12 +129,6 @@ CSRCS += vfork.c
 endif
 endif
 
-ifneq ($(CONFIG_DISABLE_PTHREAD),y)
-ifeq ($(CONFIG_PRIORITY_INHERITANCE),y)
-CSRCS += prioinherit.c
-endif # CONFIG_PRIORITY_INHERITANCE
-endif # CONFIG_DISABLE_PTHREAD
-
 ifeq ($(CONFIG_ARCH_SETJMP_H),y)
 CSRCS += setjmp.c
 endif
diff --git a/testing/ostest/ostest.h b/testing/ostest/ostest.h
index a9bd857bd..33625f5e5 100644
--- a/testing/ostest/ostest.h
+++ b/testing/ostest/ostest.h
@@ -250,6 +250,10 @@ void barrier_test(void);
 
 void priority_inheritance(void);
 
+/* schedlock.c **************************************************************/
+
+void sched_lock_test(void);
+
 /* vfork.c ******************************************************************/
 
 #if defined(CONFIG_ARCH_HAVE_VFORK) && defined(CONFIG_SCHED_WAITPID)
diff --git a/testing/ostest/ostest_main.c b/testing/ostest/ostest_main.c
index 02ae8efac..2f7a05c15 100644
--- a/testing/ostest/ostest_main.c
+++ b/testing/ostest/ostest_main.c
@@ -574,6 +574,12 @@ static int user_main(int argc, char *argv[])
       check_test_memory_usage();
 #endif /* CONFIG_PRIORITY_INHERITANCE && !CONFIG_DISABLE_PTHREAD */
 
+#ifndef CONFIG_DISABLE_PTHREAD
+      printf("\nuser_main: scheduler lock test\n");
+      sched_lock_test();
+      check_test_memory_usage();
+#endif
+
 #if defined(CONFIG_ARCH_HAVE_VFORK) && defined(CONFIG_SCHED_WAITPID)
       printf("\nuser_main: vfork() test\n");
       vfork_test();
diff --git a/testing/ostest/schedlock.c b/testing/ostest/schedlock.c
new file mode 100644
index 000000000..68c36e76a
--- /dev/null
+++ b/testing/ostest/schedlock.c
@@ -0,0 +1,274 @@
+/****************************************************************************
+ * apps/testing/ostest/schedlock.c
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/* Scheduler lock test consists of two test cases that use 2 threads with
+ * high (H) and low (L) priorities.  The H sets variable to predefined value
+ * while L tries to clear the variable.  The H manipulates with with thread
+ * priorities while scheduler is locked.  The test is pass if variable set by
+ * H is still set to predefined value after thread priority is changed.
+ *
+ *   Test case 1. The H thread locks scheduler and increase priority of L
+ *                to the H+1 priority. The test case passes if H is still
+ *                running after priority of L is increased.
+ *   Test case 2. The H thread locks scheduler and decreases it's own
+ *                priority to L-1. The test case passes if H is still
+ *                running after it's priority is decreased.
+ *
+ */
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <errno.h>
+#include <sched.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#ifdef CONFIG_ARCH_SIM
+#  include <nuttx/arch.h>
+#endif
+
+#include <sys/wait.h>
+
+#include "ostest.h"
+
+static pthread_t g_lowpri;
+static pthread_t g_highpri;
+static volatile bool g_locked;
+static volatile bool g_pass;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: highpri_thread
+ ****************************************************************************/
+
+static FAR void *highpri_thread(FAR void *parameter)
+{
+  struct sched_param param;
+  int policy;
+  bool self = (bool)(uintptr_t)parameter;
+  pthread_t thread = self ? 0 : g_lowpri;
+
+  usleep(100);
+
+  pthread_getschedparam(0, &policy, &param);
+  if (self)
+    {
+      param.sched_priority -= 2;
+    }
+  else
+    {
+      param.sched_priority += 2;
+    }
+
+  sched_lock();
+
+  g_locked = true;
+
+  pthread_setschedprio(thread, param.sched_priority);
+
+  /* Test pass if g_locked was not cleared by lowpri thread while scheduler
+   * is locked
+   */
+
+  g_pass = g_locked;
+
+  sched_unlock();
+
+  return NULL;
+}
+
+/****************************************************************************
+ * Name: lowpri_thread
+ ****************************************************************************/
+
+static FAR void *lowpri_thread(FAR void *parameter)
+{
+  /* Wait until highpri thread starts the scheduler lock test */
+
+  while (!g_locked)
+    {
+#ifdef CONFIG_ARCH_SIM
+      /* The simulator doesn't have any mechanism to do asynchronous
+       * pre-emption (basically because it doesn't have any
+       * interrupts/asynchronous events).  The simulator does "fake" a timer
+       * interrupt in up_idle() -- the idle thread that only executes when
+       * nothing else is running.  In the simulator, we cannot suspend the
+       * middle priority task, or we wouldn't have the test that we want.
+       * So, we have no option but to pump the fake clock here by calling
+       * up_idle().  Sigh!
+       */
+
+      up_idle();
+#endif
+    }
+
+  g_locked = false;
+
+  return NULL;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sched_lock_test
+ ****************************************************************************/
+
+void sched_lock_test(void)
+{
+  int i;
+
+  for (i = 0; i < 2; i++)
+    {
+      pthread_attr_t attr;
+      struct sched_param sparam;
+      int status;
+      int highprio;
+      int lowprio;
+#ifdef CONFIG_SMP
+      cpu_set_t cpu_mask;
+
+      CPU_ZERO(&cpu_mask);
+      CPU_SET(0, &cpu_mask);
+#endif
+
+      status = sched_getparam(0, &sparam);
+      if (status != 0)
+        {
+          printf("sched_lock: ERROR sched_getparam failed\n");
+          ASSERT(false);
+          sparam.sched_priority = PTHREAD_DEFAULT_PRIORITY;
+        }
+
+      highprio = sparam.sched_priority - 2;
+      lowprio = highprio - 1;
+
+      /* Start the low priority thread */
+
+      printf("sched_lock: Starting lowpri_thread at %d\n", lowprio);
+      status = pthread_attr_init(&attr);
+      if (status != 0)
+        {
+          printf("sched_lock: ERROR pthread_attr_init failed, status=%d\n",
+                 status);
+          ASSERT(false);
+        }
+
+      sparam.sched_priority = lowprio;
+      status = pthread_attr_setschedparam(&attr, &sparam);
+      if (status != OK)
+        {
+          printf("sched_lock: "
+                 "ERROR pthread_attr_setschedparam failed, status=%d\n",
+                  status);
+          ASSERT(false);
+        }
+      else
+        {
+          printf("sched_lock: Set lowpri_thread priority to %d\n",
+                 sparam.sched_priority);
+        }
+
+#ifdef CONFIG_SMP
+      pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpu_mask);
+#endif
+
+      FFLUSH();
+
+      status = pthread_create(&g_lowpri, &attr, lowpri_thread, NULL);
+      if (status != 0)
+        {
+          printf("sched_lock: ERROR pthread_create failed, status=%d\n",
+                 status);
+          ASSERT(false);
+        }
+
+      /* Start the high priority thread */
+
+      printf("sched_lock: Starting highpri_thread at %d\n", highprio);
+      status = pthread_attr_init(&attr);
+      if (status != 0)
+        {
+          printf("sched_lock: ERROR pthread_attr_init failed, status=%d\n",
+                 status);
+          ASSERT(false);
+        }
+
+      sparam.sched_priority = highprio;
+      status = pthread_attr_setschedparam(&attr, &sparam);
+      if (status != OK)
+        {
+          printf("sched_lock: "
+                 "ERROR pthread_attr_setschedparam failed, status=%d\n",
+                  status);
+          ASSERT(false);
+        }
+      else
+        {
+          printf("sched_lock: Set highpri_thread priority to %d\n",
+                 sparam.sched_priority);
+        }
+
+#ifdef CONFIG_SMP
+      pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpu_mask);
+#endif
+
+      FFLUSH();
+
+      status = pthread_create(&g_highpri, &attr, highpri_thread,
+                              (FAR void *)(uintptr_t)(i == 0));
+      if (status != 0)
+        {
+          printf("sched_lock: ERROR pthread_create failed, status=%d\n",
+                 status);
+          ASSERT(false);
+        }
+
+      printf("sched_lock: Waiting...\n");
+      sleep(1);
+
+      pthread_join(g_highpri, NULL);
+      pthread_join(g_lowpri, NULL);
+
+      if (!g_pass)
+        {
+          printf("sched_lock: ERROR: FAIL pre-emption occurred "
+                 "while scheduler was locked.\n");
+          ASSERT(false);
+        }
+      else
+        {
+          printf("sched_lock: PASSED No pre-emption occurred "
+                 "while scheduler was locked.\n");
+        }
+    }
+
+  printf("sched_lock: Finished\n");
+  FFLUSH();
+}

Reply via email to