SMP: Add up_cpustart and up_cpurestart protoypes; fix some problems in sched_addreadytorun; first cut at SMP version of up_mergepending.
This commit is contained in:
parent
85f663a8ee
commit
64b3ce8775
@ -1711,6 +1711,51 @@ int up_cpundx(void);
|
||||
int up_cpustart(int cpu, main_t idletask, pid_t pid);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_cpustop
|
||||
*
|
||||
* Description:
|
||||
* Save the state of the current task at the head of the
|
||||
* g_assignedtasks[cpu] task list and then stop the CPU.
|
||||
*
|
||||
* This function is called by the OS when the logic executing on one CPU
|
||||
* needs to modify the state of the g_assignedtasks[cpu] list for another
|
||||
* CPU.
|
||||
*
|
||||
* Input Parameters:
|
||||
* cpu - The index of the CPU to be stopped/
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
int up_cpustop(int cpu);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_cpurestart
|
||||
*
|
||||
* Description:
|
||||
* Restart the cpu, restoring the state of the task at the head of the
|
||||
* g_assignedtasks[cpu] list.
|
||||
*
|
||||
* This function is called after up_cpustop in order resume operation of
|
||||
* the CPU after modifying its g_assignedtasks[cpu] list.
|
||||
*
|
||||
* Input Parameters:
|
||||
* cpu - The index of the CPU being re-started.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
int up_cpurestart(int cpu);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_romgetc
|
||||
*
|
||||
|
@ -46,26 +46,6 @@
|
||||
|
||||
#include "sched/sched.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Type Declarations
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Variables
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
@ -170,49 +170,61 @@ bool sched_addreadytorun(FAR struct tcb_s *btcb)
|
||||
FAR struct tcb_s *rtcb;
|
||||
FAR struct tcb_s *next;
|
||||
FAR dq_queue_t *tasklist;
|
||||
uint8_t minprio;
|
||||
int task_state;
|
||||
int cpu;
|
||||
bool switched;
|
||||
bool doswitch;
|
||||
int i;
|
||||
|
||||
/* Find the CPU that is executing the lowest priority task (possibly its
|
||||
* IDLE task).
|
||||
*/
|
||||
/* Check if the blocked TCB is already assigned to a CPU */
|
||||
|
||||
rtcb = NULL;
|
||||
minprio = SCHED_PRIORITY_MAX;
|
||||
cpu = 0;
|
||||
|
||||
for (i = 0; i < CONFIG_SMP_NCPUS; i++)
|
||||
if ((btcb->flags & TCB_FLAG_CPU_ASSIGNED) != 0)
|
||||
{
|
||||
FAR struct tcb_s *candidate =
|
||||
(FAR struct tcb_s *)g_assignedtasks[i].head;
|
||||
/* Yes.. that that is the CPU we must use */
|
||||
|
||||
/* If this thread is executing its IDLE task, the use it. The IDLE
|
||||
* task is always the last task in the assigned task list.
|
||||
cpu = btcb->cpu;
|
||||
rtcb = (FAR struct tcb_s *)g_assignedtasks[cpu].head;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t minprio;
|
||||
int i;
|
||||
|
||||
/* Otherwise, find the CPU that is executing the lowest priority task
|
||||
* (possibly its IDLE task).
|
||||
*/
|
||||
|
||||
if (candidate->flink == NULL)
|
||||
rtcb = NULL;
|
||||
minprio = SCHED_PRIORITY_MAX;
|
||||
cpu = 0;
|
||||
|
||||
for (i = 0; i < CONFIG_SMP_NCPUS; i++)
|
||||
{
|
||||
/* The IDLE task should always be assigned to this CPU and have a
|
||||
* priority zero.
|
||||
FAR struct tcb_s *candidate =
|
||||
(FAR struct tcb_s *)g_assignedtasks[i].head;
|
||||
|
||||
/* If this thread is executing its IDLE task, the use it. The
|
||||
* IDLE task is always the last task in the assigned task list.
|
||||
*/
|
||||
|
||||
DEBUGASSERT((candidate->flags & TCB_FLAG_CPU_ASSIGNED) != 0 &&
|
||||
candidate->sched_priority == 0);
|
||||
if (candidate->flink == NULL)
|
||||
{
|
||||
/* The IDLE task should always be assigned to this CPU and
|
||||
* have a priority of zero.
|
||||
*/
|
||||
|
||||
rtcb = candidate;
|
||||
cpu = i;
|
||||
break;
|
||||
}
|
||||
else if (candidate->sched_priority < minprio)
|
||||
{
|
||||
DEBUGASSERT(candidate->sched_priority > 0);
|
||||
DEBUGASSERT(candidate->sched_priority == 0);
|
||||
|
||||
rtcb = candidate;
|
||||
cpu = i;
|
||||
rtcb = candidate;
|
||||
cpu = i;
|
||||
break;
|
||||
}
|
||||
else if (candidate->sched_priority < minprio)
|
||||
{
|
||||
DEBUGASSERT(candidate->sched_priority > 0);
|
||||
|
||||
rtcb = candidate;
|
||||
cpu = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,20 +270,46 @@ bool sched_addreadytorun(FAR struct tcb_s *btcb)
|
||||
btcb->task_state = TSTATE_TASK_PENDING;
|
||||
doswitch = false;
|
||||
}
|
||||
else
|
||||
else if (task_state == TSTATE_TASK_READYTORUN)
|
||||
{
|
||||
/* The new btcb was added either (1) in the middle of the assigned
|
||||
* task list (the btcb->cpu field is already valid) or (2) was
|
||||
* added to the ready-to-run list (the btcb->cpu field does not
|
||||
* matter). Either way, it won't be running.
|
||||
*
|
||||
* Add the task to the ready-to-run (but not running) task list
|
||||
*/
|
||||
|
||||
(void)sched_addprioritized(btcb, (FAR dq_queue_t *)&g_readytorun);
|
||||
|
||||
btcb->task_state = TSTATE_TASK_READYTORUN;
|
||||
doswitch = false;
|
||||
}
|
||||
else /* (task_state == TSTATE_TASK_ASSIGNED || task_state == TSTATE_TASK_RUNNING) */
|
||||
{
|
||||
int me = this_cpu();
|
||||
|
||||
/* If we are modifying some assigned task list other than our own, we will
|
||||
* need to stop that CPU.
|
||||
*/
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
DEBUGVERIFY(up_cpustop(cpu));
|
||||
}
|
||||
|
||||
/* Add the task to the list corresponding to the selected state
|
||||
* and check if a context switch will occur
|
||||
*/
|
||||
|
||||
tasklist = TLIST_HEAD(task_state, cpu);
|
||||
tasklist = (FAR dq_queue_t *)g_assignedtasks[cpu].head;
|
||||
switched = sched_addprioritized(btcb, tasklist);
|
||||
|
||||
/* If the selected task was the g_assignedtasks[] list, then a context
|
||||
* swith will occur.
|
||||
*/
|
||||
|
||||
if (switched && task_state != TSTATE_TASK_READYTORUN)
|
||||
if (switched)
|
||||
{
|
||||
/* The new btcb was added at the head of the ready-to-run list. It
|
||||
* is now the new active task!
|
||||
@ -310,7 +348,7 @@ bool sched_addreadytorun(FAR struct tcb_s *btcb)
|
||||
* lifting machinery.
|
||||
*/
|
||||
|
||||
next = (FAR dq_queue_t *)btcb->flink;
|
||||
next = (FAR struct tcb_s *)btcb->flink;
|
||||
ASSERT(!rtcb->lockcount && next != NULL);
|
||||
|
||||
if ((btcb->flags & TCB_FLAG_CPU_ASSIGNED) != 0)
|
||||
@ -328,23 +366,28 @@ bool sched_addreadytorun(FAR struct tcb_s *btcb)
|
||||
*/
|
||||
|
||||
next->task_state = TSTATE_TASK_READYTORUN;
|
||||
(void)sched_addprioritized(btcb, &g_readytorun);
|
||||
(void)sched_addprioritized(btcb,
|
||||
(FAR dq_queue_t *)&g_readytorun);
|
||||
}
|
||||
|
||||
doswitch = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The new btcb was added either (1) in the middle of the assigned
|
||||
* task list (the btcb->cpu field is already valid) or (2) was
|
||||
* added to the ready-to-run list (the btcb->cpu field does not
|
||||
* matter). Either way, it won't be running.
|
||||
*/
|
||||
/* No context switch. Assign the CPU and set the assigned state */
|
||||
|
||||
DEBUGASSERT(task_state != TSTATE_TASK_RUNNING);
|
||||
DEBUGASSERT(task_state == TSTATE_TASK_ASSIGNED);
|
||||
|
||||
btcb->task_state = TSTATE_TASK_READYTORUN;
|
||||
doswitch = false;
|
||||
btcb->cpu = cpu;
|
||||
btcb->task_state = TSTATE_TASK_ASSIGNED;
|
||||
}
|
||||
|
||||
/* All done, restart the other that CPU. */
|
||||
|
||||
if (cpu != me)
|
||||
{
|
||||
DEBUGVERIFY(up_cpurestart(cpu));
|
||||
doswitch = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* sched/sched/sched_mergepending.c
|
||||
*
|
||||
* Copyright (C) 2007, 2009, 2012 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2007, 2009, 2012, 2016 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -55,13 +55,14 @@
|
||||
*
|
||||
* Description:
|
||||
* This function merges the prioritized g_pendingtasks list into the
|
||||
* prioritized g_readytorun task list.
|
||||
* prioritized ready-to-run task list.
|
||||
*
|
||||
* Inputs:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* true if the head of the g_readytorun task list has changed.
|
||||
* true if the head of the ready-to-run task list has changed indicating
|
||||
* a context switch is needed.
|
||||
*
|
||||
* Assumptions:
|
||||
* - The caller has established a critical section before
|
||||
@ -72,75 +73,82 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
bool sched_mergepending(void)
|
||||
{
|
||||
FAR struct tcb_s *pndtcb;
|
||||
FAR struct tcb_s *pndnext;
|
||||
FAR struct tcb_s *rtrtcb;
|
||||
FAR struct tcb_s *rtrprev;
|
||||
FAR struct tcb_s *ptcb;
|
||||
FAR struct tcb_s *pnext;
|
||||
FAR struct tcb_s *rtcb;
|
||||
FAR struct tcb_s *rprev;
|
||||
bool ret = false;
|
||||
|
||||
/* Initialize the inner search loop */
|
||||
|
||||
rtrtcb = this_task();
|
||||
rtcb = this_task();
|
||||
|
||||
/* Process every TCB in the g_pendingtasks list */
|
||||
|
||||
for (pndtcb = (FAR struct tcb_s *)g_pendingtasks.head; pndtcb; pndtcb = pndnext)
|
||||
for (ptcb = (FAR struct tcb_s *)g_pendingtasks.head;
|
||||
ptcb;
|
||||
ptcb = pnext)
|
||||
{
|
||||
pndnext = pndtcb->flink;
|
||||
pnext = ptcb->flink;
|
||||
|
||||
/* Search the g_readytorun list to find the location to insert the
|
||||
* new pndtcb. Each is list is maintained in ascending sched_priority
|
||||
/* REVISIT: Why don't we just remove the ptcb from pending task list
|
||||
* and call sched_addreadytorun?
|
||||
*/
|
||||
|
||||
/* Search the ready-to-run list to find the location to insert the
|
||||
* new ptcb. Each is list is maintained in ascending sched_priority
|
||||
* order.
|
||||
*/
|
||||
|
||||
for (;
|
||||
(rtrtcb && pndtcb->sched_priority <= rtrtcb->sched_priority);
|
||||
rtrtcb = rtrtcb->flink);
|
||||
(rtcb && ptcb->sched_priority <= rtcb->sched_priority);
|
||||
rtcb = rtcb->flink);
|
||||
|
||||
/* Add the pndtcb to the spot found in the list. Check if the
|
||||
* pndtcb goes at the ends of the g_readytorun list. This would be
|
||||
/* Add the ptcb to the spot found in the list. Check if the
|
||||
* ptcb goes at the ends of the ready-to-run list. This would be
|
||||
* error condition since the idle test must always be at the end of
|
||||
* the g_readytorun list!
|
||||
* the ready-to-run list!
|
||||
*/
|
||||
|
||||
ASSERT(rtrtcb);
|
||||
ASSERT(rtcb);
|
||||
|
||||
/* The pndtcb goes just before rtrtcb */
|
||||
/* The ptcb goes just before rtcb */
|
||||
|
||||
rtrprev = rtrtcb->blink;
|
||||
if (!rtrprev)
|
||||
rprev = rtcb->blink;
|
||||
if (!rprev)
|
||||
{
|
||||
/* Special case: Inserting pndtcb at the head of the list */
|
||||
/* Special case: Inserting ptcb at the head of the list */
|
||||
/* Inform the instrumentation layer that we are switching tasks */
|
||||
|
||||
sched_note_switch(rtrtcb, pndtcb);
|
||||
sched_note_switch(rtcb, ptcb);
|
||||
|
||||
/* Then insert at the head of the list */
|
||||
|
||||
pndtcb->flink = rtrtcb;
|
||||
pndtcb->blink = NULL;
|
||||
rtrtcb->blink = pndtcb;
|
||||
g_readytorun.head = (FAR dq_entry_t *)pndtcb;
|
||||
rtrtcb->task_state = TSTATE_TASK_READYTORUN;
|
||||
pndtcb->task_state = TSTATE_TASK_RUNNING;
|
||||
ret = true;
|
||||
ptcb->flink = rtcb;
|
||||
ptcb->blink = NULL;
|
||||
rtcb->blink = ptcb;
|
||||
g_readytorun.head = (FAR dq_entry_t *)ptcb;
|
||||
rtcb->task_state = TSTATE_TASK_READYTORUN;
|
||||
ptcb->task_state = TSTATE_TASK_RUNNING;
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Insert in the middle of the list */
|
||||
|
||||
pndtcb->flink = rtrtcb;
|
||||
pndtcb->blink = rtrprev;
|
||||
rtrprev->flink = pndtcb;
|
||||
rtrtcb->blink = pndtcb;
|
||||
pndtcb->task_state = TSTATE_TASK_READYTORUN;
|
||||
ptcb->flink = rtcb;
|
||||
ptcb->blink = rprev;
|
||||
rprev->flink = ptcb;
|
||||
rtcb->blink = ptcb;
|
||||
ptcb->task_state = TSTATE_TASK_READYTORUN;
|
||||
}
|
||||
|
||||
/* Set up for the next time through */
|
||||
|
||||
rtrtcb = pndtcb;
|
||||
rtcb = ptcb;
|
||||
}
|
||||
|
||||
/* Mark the input list empty */
|
||||
@ -150,3 +158,48 @@ bool sched_mergepending(void)
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* !CONFIG_SMP */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sched_mergepending
|
||||
*
|
||||
* Description:
|
||||
* This function merges the prioritized g_pendingtasks list into the
|
||||
* prioritized ready-to-run task list.
|
||||
*
|
||||
* Inputs:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* true if the head of the ready-to-run task list has changed indicating
|
||||
* a context switch is needed.
|
||||
*
|
||||
* Assumptions:
|
||||
* - The caller has established a critical section before
|
||||
* calling this function (calling sched_lock() first is NOT
|
||||
* a good idea -- use irqsave()).
|
||||
* - The caller handles the condition that occurs if the
|
||||
* the head of the sched_mergTSTATE_TASK_PENDINGs is changed.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
bool sched_mergepending(void)
|
||||
{
|
||||
FAR struct tcb_s *ptcb;
|
||||
bool ret = false;
|
||||
|
||||
/* Remove and process every TCB in the g_pendingtasks list */
|
||||
|
||||
for (ptcb = (FAR struct tcb_s *)dq_remfirst((FAR dq_queue_t *)&g_pendingtasks);
|
||||
ptcb != NULL;
|
||||
ptcb = (FAR struct tcb_s *)dq_remfirst((FAR dq_queue_t *)&g_pendingtasks))
|
||||
{
|
||||
/* Add the pending task to the correct ready-to-run list */
|
||||
|
||||
ret |= sched_addreadytorun(ptcb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_SMP */
|
||||
|
Loading…
Reference in New Issue
Block a user