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, ¶m); + 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(); +}
