From ce67d717b8defcb3755f947aab71e0b2e96e3852 Mon Sep 17 00:00:00 2001 From: Petro Karashchenko Date: Tue, 11 Apr 2023 16:06:11 +0300 Subject: [PATCH] testing/ostest: add test case for task priority change with locked scheduler Signed-off-by: Petro Karashchenko --- testing/ostest/Makefile | 14 +- testing/ostest/ostest.h | 6 + testing/ostest/ostest_main.c | 6 + testing/ostest/schedlock.c | 241 +++++++++++++++++++++++++++++++++++ 4 files changed, 261 insertions(+), 6 deletions(-) create mode 100644 testing/ostest/schedlock.c diff --git a/testing/ostest/Makefile b/testing/ostest/Makefile index 98a15ca4c03..80f39d17beb 100644 --- a/testing/ostest/Makefile +++ b/testing/ostest/Makefile @@ -97,6 +97,14 @@ endif ifeq ($(CONFIG_SCHED_WORKQUEUE),y) CSRCS += wqueue.c endif + +ifeq ($(CONFIG_PRIORITY_INHERITANCE),y) +CSRCS += prioinherit.c +endif + +ifneq ($(CONFIG_ARCH_SIM),y) +CSRCS += schedlock.c +endif endif # CONFIG_DISABLE_PTHREAD ifneq ($(CONFIG_DISABLE_MQUEUE),y) @@ -118,12 +126,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 22989fa591b..06fb720361a 100644 --- a/testing/ostest/ostest.h +++ b/testing/ostest/ostest.h @@ -242,6 +242,12 @@ void barrier_test(void); void priority_inheritance(void); +/* schedlock.c ***************************************************************/ + +#ifndef CONFIG_ARCH_SIM +void sched_lock_test(void); +#endif + /* 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 2ed6b20ebe8..c06fa580760 100644 --- a/testing/ostest/ostest_main.c +++ b/testing/ostest/ostest_main.c @@ -564,6 +564,12 @@ static int user_main(int argc, char *argv[]) check_test_memory_usage(); #endif /* CONFIG_PRIORITY_INHERITANCE && !CONFIG_DISABLE_PTHREAD */ +#if !defined(CONFIG_ARCH_SIM) && !defined(CONFIG_DISABLE_PTHREAD) + printf("\nuser_main: priority test\n"); + sched_lock_test(); + check_test_memory_usage(); +#endif /* !CONFIG_ARCH_SIM && !CONFIG_DISABLE_PTHREAD */ + #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 00000000000..9c8dfea68e5 --- /dev/null +++ b/testing/ostest/schedlock.c @@ -0,0 +1,241 @@ +/**************************************************************************** + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "ostest.h" + +#include + +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; + + nxsched_set_param(thread, ¶m); + + /* 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) + { + } + + 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("priority: 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("priority: Starting lowpri_thread at %d\n", lowprio); + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("priority: 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("priority: " + "ERROR pthread_attr_setschedparam failed, status=%d\n", + status); + ASSERT(false); + } + else + { + printf("priority: 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("priority: ERROR pthread_create failed, status=%d\n", + status); + ASSERT(false); + } + + /* Start the high priority thread */ + + printf("priority: Starting highpri_thread at %d\n", highprio); + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("priority: 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("priority: " + "ERROR pthread_attr_setschedparam failed, status=%d\n", + status); + ASSERT(false); + } + else + { + printf("priority: 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("priority: ERROR pthread_create failed, status=%d\n", + status); + ASSERT(false); + } + + printf("priority: Waiting...\n"); + sleep(1); + + waitpid(g_highpri, &status, 0); + waitpid(g_lowpri, &status, 0); + + if (!g_pass) + { + printf("priority: ERROR: FAIL pre-emption occurred" + "while scheduler was locked.\n"); + ASSERT(false); + } + else + { + printf("priority: PASSED No pre-emption occurred" + "while scheduler was locked.\n"); + } + } + + printf("priority: Finished\n"); + FFLUSH(); +}