2014-10-07 15:41:52 +02:00
|
|
|
/****************************************************************************
|
2021-03-08 22:39:04 +01:00
|
|
|
* sched/wqueue/kwork_inherit.c
|
2014-10-07 15:41:52 +02:00
|
|
|
*
|
2020-03-11 21:23:38 +01:00
|
|
|
* 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
|
2014-10-07 15:41:52 +02:00
|
|
|
*
|
2020-03-11 21:23:38 +01:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2014-10-07 15:41:52 +02:00
|
|
|
*
|
2020-03-11 21:23:38 +01:00
|
|
|
* 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.
|
2014-10-07 15:41:52 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Included Files
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
|
|
|
|
#include <sched.h>
|
2021-05-18 08:59:14 +02:00
|
|
|
#include <assert.h>
|
2021-05-14 04:45:57 +02:00
|
|
|
#include <debug.h>
|
2014-10-07 15:41:52 +02:00
|
|
|
|
2016-02-14 15:17:46 +01:00
|
|
|
#include <nuttx/irq.h>
|
2014-10-07 15:41:52 +02:00
|
|
|
#include <nuttx/wqueue.h>
|
|
|
|
|
|
|
|
#include "sched/sched.h"
|
2014-10-10 14:22:51 +02:00
|
|
|
#include "wqueue/wqueue.h"
|
2014-10-07 15:41:52 +02:00
|
|
|
|
|
|
|
#if defined(CONFIG_SCHED_WORKQUEUE) && defined(CONFIG_SCHED_LPWORK) && \
|
|
|
|
defined(CONFIG_PRIORITY_INHERITANCE)
|
|
|
|
|
|
|
|
/****************************************************************************
|
2014-10-11 01:47:39 +02:00
|
|
|
* Private Functions
|
2014-10-07 15:41:52 +02:00
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
2014-10-11 01:47:39 +02:00
|
|
|
* Name: lpwork_boostworker
|
2014-10-07 15:41:52 +02:00
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Called by the work queue client to assure that the priority of the low-
|
|
|
|
* priority worker thread is at least at the requested level, reqprio. This
|
|
|
|
* function would normally be called just before calling work_queue().
|
|
|
|
*
|
2018-03-13 16:52:27 +01:00
|
|
|
* Input Parameters:
|
2014-10-07 15:41:52 +02:00
|
|
|
* reqprio - Requested minimum worker thread priority
|
|
|
|
*
|
2018-02-01 17:00:02 +01:00
|
|
|
* Returned Value:
|
2014-10-07 15:41:52 +02:00
|
|
|
* None
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2014-10-11 01:47:39 +02:00
|
|
|
static void lpwork_boostworker(pid_t wpid, uint8_t reqprio)
|
2014-10-07 15:41:52 +02:00
|
|
|
{
|
|
|
|
FAR struct tcb_s *wtcb;
|
|
|
|
|
2014-10-11 01:47:39 +02:00
|
|
|
/* Get the TCB of the low priority worker thread from the process ID. */
|
2014-10-08 01:11:26 +02:00
|
|
|
|
2020-05-09 16:04:45 +02:00
|
|
|
wtcb = nxsched_get_tcb(wpid);
|
2014-10-11 01:47:39 +02:00
|
|
|
DEBUGASSERT(wtcb);
|
2014-10-07 15:41:52 +02:00
|
|
|
|
2022-05-24 00:06:10 +02:00
|
|
|
/* REVISIT: Priority multi-boost is not supported */
|
|
|
|
|
|
|
|
DEBUGASSERT(wtcb->boost_priority == 0);
|
|
|
|
|
2014-10-07 15:41:52 +02:00
|
|
|
/* If the priority of the client thread that is greater than the base
|
|
|
|
* priority of the worker thread, then we may need to adjust the worker
|
|
|
|
* thread's priority now or later to that priority.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (reqprio > wtcb->base_priority)
|
|
|
|
{
|
2022-05-24 00:06:10 +02:00
|
|
|
/* Save boost priority value as it might be needed in case of multiple
|
|
|
|
* re-prioritisations happen, then the priority of the thread can't go
|
|
|
|
* below the boost priority value until priority boost is canceled.
|
2014-10-07 15:41:52 +02:00
|
|
|
*/
|
|
|
|
|
2022-05-24 00:06:10 +02:00
|
|
|
wtcb->boost_priority = reqprio;
|
2014-10-07 15:41:52 +02:00
|
|
|
|
2022-05-24 00:06:10 +02:00
|
|
|
/* If the priority of the client thread that is less than of equal to
|
|
|
|
* the priority of the worker thread, then do nothing because the
|
|
|
|
* thread is already running at a sufficient priority.
|
|
|
|
*/
|
2014-10-07 15:41:52 +02:00
|
|
|
|
2022-05-24 00:06:10 +02:00
|
|
|
if (reqprio > wtcb->sched_priority)
|
2014-10-07 15:41:52 +02:00
|
|
|
{
|
2022-05-24 00:06:10 +02:00
|
|
|
/* Raise the priority of the worker thread. This cannot cause
|
|
|
|
* context switch because we have preemption disabled. The task
|
|
|
|
* will be marked "pending" and the switch will occur during
|
|
|
|
* sched_unlock() processing.
|
2014-10-07 15:41:52 +02:00
|
|
|
*/
|
|
|
|
|
2022-05-24 00:06:10 +02:00
|
|
|
nxsched_set_priority(wtcb, reqprio);
|
2014-10-07 15:41:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2014-10-11 01:47:39 +02:00
|
|
|
* Name: lpwork_restoreworker
|
2014-10-07 15:41:52 +02:00
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* This function is called to restore the priority after it was previously
|
|
|
|
* boosted. This is often done by client logic on the worker thread when
|
|
|
|
* the scheduled work completes. It will check if we need to drop the
|
|
|
|
* priority of the worker thread.
|
|
|
|
*
|
2018-03-13 16:52:27 +01:00
|
|
|
* Input Parameters:
|
2014-10-07 15:41:52 +02:00
|
|
|
* reqprio - Previously requested minimum worker thread priority to be
|
|
|
|
* "unboosted"
|
|
|
|
*
|
2018-02-01 17:00:02 +01:00
|
|
|
* Returned Value:
|
2014-10-07 15:41:52 +02:00
|
|
|
* None
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2014-10-11 01:47:39 +02:00
|
|
|
static void lpwork_restoreworker(pid_t wpid, uint8_t reqprio)
|
2014-10-07 15:41:52 +02:00
|
|
|
{
|
|
|
|
FAR struct tcb_s *wtcb;
|
|
|
|
|
2014-10-11 01:47:39 +02:00
|
|
|
/* Get the TCB of the low priority worker thread from the process ID. */
|
2014-10-07 15:41:52 +02:00
|
|
|
|
2020-05-09 16:04:45 +02:00
|
|
|
wtcb = nxsched_get_tcb(wpid);
|
2014-10-11 01:47:39 +02:00
|
|
|
DEBUGASSERT(wtcb);
|
2014-10-07 15:41:52 +02:00
|
|
|
|
2022-05-24 00:06:10 +02:00
|
|
|
/* REVISIT: Priority multi-boost is not supported. */
|
|
|
|
|
|
|
|
DEBUGASSERT(wtcb->boost_priority == reqprio);
|
|
|
|
|
|
|
|
/* Clear the threat boost priority. */
|
|
|
|
|
|
|
|
wtcb->boost_priority = 0;
|
|
|
|
|
2014-10-07 15:41:52 +02:00
|
|
|
/* Was the priority of the worker thread boosted? If so, then drop its
|
|
|
|
* priority back to the correct level. What is the correct level?
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (wtcb->sched_priority != wtcb->base_priority)
|
|
|
|
{
|
2022-05-24 00:06:10 +02:00
|
|
|
FAR struct semholder_s *pholder;
|
|
|
|
uint8_t wpriority;
|
2014-10-07 15:41:52 +02:00
|
|
|
|
2022-05-24 00:06:10 +02:00
|
|
|
/* We attempt to restore task priority to its base priority. If there
|
|
|
|
* is any task with the higher priority waiting for the semaphore
|
|
|
|
* held by wtcb then this value will be overwritten.
|
|
|
|
*/
|
2014-10-07 15:41:52 +02:00
|
|
|
|
2022-05-24 00:06:10 +02:00
|
|
|
wpriority = wtcb->base_priority;
|
2014-10-07 15:41:52 +02:00
|
|
|
|
2022-05-24 00:06:10 +02:00
|
|
|
/* Try to find the highest priority across all the tasks that are
|
|
|
|
* waiting for any semaphore held by wtcb.
|
2014-10-07 15:41:52 +02:00
|
|
|
*/
|
|
|
|
|
2022-05-24 00:06:10 +02:00
|
|
|
for (pholder = wtcb->holdsem; pholder != NULL;
|
|
|
|
pholder = pholder->tlink)
|
2014-10-07 15:41:52 +02:00
|
|
|
{
|
2022-05-24 00:06:10 +02:00
|
|
|
FAR struct tcb_s *stcb;
|
2014-10-07 15:41:52 +02:00
|
|
|
|
2022-05-24 00:06:10 +02:00
|
|
|
stcb = (FAR struct tcb_s *)dq_peek(SEM_WAITLIST(pholder->sem));
|
2014-10-07 15:41:52 +02:00
|
|
|
|
2022-05-24 00:06:10 +02:00
|
|
|
if (stcb != NULL && stcb->sched_priority > wpriority)
|
2014-10-07 15:41:52 +02:00
|
|
|
{
|
2022-05-24 00:06:10 +02:00
|
|
|
wpriority = stcb->sched_priority;
|
2014-10-07 15:41:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-24 00:06:10 +02:00
|
|
|
/* Apply the selected priority to the worker thread (hopefully back
|
|
|
|
* to the threads base_priority).
|
2014-10-07 15:41:52 +02:00
|
|
|
*/
|
|
|
|
|
2022-05-24 00:06:10 +02:00
|
|
|
nxsched_set_priority(wtcb, wpriority);
|
2014-10-07 15:41:52 +02:00
|
|
|
}
|
2014-10-11 01:47:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Public Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: lpwork_boostpriority
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Called by the work queue client to assure that the priority of the low-
|
|
|
|
* priority worker thread is at least at the requested level, reqprio. This
|
|
|
|
* function would normally be called just before calling work_queue().
|
|
|
|
*
|
2018-03-13 16:52:27 +01:00
|
|
|
* Input Parameters:
|
2014-10-11 01:47:39 +02:00
|
|
|
* reqprio - Requested minimum worker thread priority
|
|
|
|
*
|
2018-02-01 17:00:02 +01:00
|
|
|
* Returned Value:
|
2014-10-11 01:47:39 +02:00
|
|
|
* None
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void lpwork_boostpriority(uint8_t reqprio)
|
|
|
|
{
|
|
|
|
irqstate_t flags;
|
|
|
|
int wndx;
|
|
|
|
|
|
|
|
/* Clip to the configured maximum priority */
|
|
|
|
|
|
|
|
if (reqprio > CONFIG_SCHED_LPWORKPRIOMAX)
|
|
|
|
{
|
|
|
|
reqprio = CONFIG_SCHED_LPWORKPRIOMAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Prevent context switches until we get the priorities right */
|
|
|
|
|
2016-02-14 15:17:46 +01:00
|
|
|
flags = enter_critical_section();
|
2014-10-11 01:47:39 +02:00
|
|
|
sched_lock();
|
|
|
|
|
|
|
|
/* Adjust the priority of every worker thread */
|
|
|
|
|
|
|
|
for (wndx = 0; wndx < CONFIG_SCHED_LPNTHREADS; wndx++)
|
|
|
|
{
|
|
|
|
lpwork_boostworker(g_lpwork.worker[wndx].pid, reqprio);
|
|
|
|
}
|
|
|
|
|
|
|
|
sched_unlock();
|
2016-02-14 15:17:46 +01:00
|
|
|
leave_critical_section(flags);
|
2014-10-11 01:47:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: lpwork_restorepriority
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* This function is called to restore the priority after it was previously
|
|
|
|
* boosted. This is often done by client logic on the worker thread when
|
|
|
|
* the scheduled work completes. It will check if we need to drop the
|
|
|
|
* priority of the worker thread.
|
|
|
|
*
|
2018-03-13 16:52:27 +01:00
|
|
|
* Input Parameters:
|
2014-10-11 01:47:39 +02:00
|
|
|
* reqprio - Previously requested minimum worker thread priority to be
|
|
|
|
* "unboosted"
|
|
|
|
*
|
2018-02-01 17:00:02 +01:00
|
|
|
* Returned Value:
|
2014-10-11 01:47:39 +02:00
|
|
|
* None
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void lpwork_restorepriority(uint8_t reqprio)
|
|
|
|
{
|
|
|
|
irqstate_t flags;
|
|
|
|
int wndx;
|
|
|
|
|
|
|
|
/* Clip to the configured maximum priority */
|
|
|
|
|
|
|
|
if (reqprio > CONFIG_SCHED_LPWORKPRIOMAX)
|
|
|
|
{
|
|
|
|
reqprio = CONFIG_SCHED_LPWORKPRIOMAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Prevent context switches until we get the priorities right */
|
|
|
|
|
2016-02-14 15:17:46 +01:00
|
|
|
flags = enter_critical_section();
|
2014-10-11 01:47:39 +02:00
|
|
|
sched_lock();
|
|
|
|
|
|
|
|
/* Adjust the priority of every worker thread */
|
|
|
|
|
|
|
|
for (wndx = 0; wndx < CONFIG_SCHED_LPNTHREADS; wndx++)
|
|
|
|
{
|
|
|
|
lpwork_restoreworker(g_lpwork.worker[wndx].pid, reqprio);
|
|
|
|
}
|
2014-10-07 15:41:52 +02:00
|
|
|
|
|
|
|
sched_unlock();
|
2016-02-14 15:17:46 +01:00
|
|
|
leave_critical_section(flags);
|
2014-10-07 15:41:52 +02:00
|
|
|
}
|
|
|
|
|
2017-06-14 21:42:56 +02:00
|
|
|
#endif /* CONFIG_SCHED_WORKQUEUE && CONFIG_SCHED_LPWORK && \
|
|
|
|
* CONFIG_PRIORITY_INHERITANCE */
|