Skip to content

Commit

Permalink
testing/ostest: add test case for task priority change with locked sc…
Browse files Browse the repository at this point in the history
…heduler

Signed-off-by: Petro Karashchenko <petro.karashchenko@gmail.com>
  • Loading branch information
pkarashchenko committed Apr 12, 2023
1 parent 445352a commit c79b76d
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 8 deletions.
13 changes: 5 additions & 8 deletions testing/ostest/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,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

ifneq ($(CONFIG_TLS_NELEM),0)
CSRCS += specific.c
Expand Down Expand Up @@ -97,6 +96,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)
Expand All @@ -118,12 +121,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
Expand Down
4 changes: 4 additions & 0 deletions testing/ostest/ostest.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,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)
Expand Down
6 changes: 6 additions & 0 deletions testing/ostest/ostest_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,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();
Expand Down
259 changes: 259 additions & 0 deletions testing/ostest/schedlock.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
/****************************************************************************
* 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 <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();
}

0 comments on commit c79b76d

Please sign in to comment.