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);
|
int up_cpustart(int cpu, main_t idletask, pid_t pid);
|
||||||
#endif
|
#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
|
* Name: up_romgetc
|
||||||
*
|
*
|
||||||
|
@ -46,26 +46,6 @@
|
|||||||
|
|
||||||
#include "sched/sched.h"
|
#include "sched/sched.h"
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Pre-processor Definitions
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Private Type Declarations
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Public Data
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Private Variables
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Private Function Prototypes
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -170,15 +170,27 @@ bool sched_addreadytorun(FAR struct tcb_s *btcb)
|
|||||||
FAR struct tcb_s *rtcb;
|
FAR struct tcb_s *rtcb;
|
||||||
FAR struct tcb_s *next;
|
FAR struct tcb_s *next;
|
||||||
FAR dq_queue_t *tasklist;
|
FAR dq_queue_t *tasklist;
|
||||||
uint8_t minprio;
|
|
||||||
int task_state;
|
int task_state;
|
||||||
int cpu;
|
int cpu;
|
||||||
bool switched;
|
bool switched;
|
||||||
bool doswitch;
|
bool doswitch;
|
||||||
|
|
||||||
|
/* Check if the blocked TCB is already assigned to a CPU */
|
||||||
|
|
||||||
|
if ((btcb->flags & TCB_FLAG_CPU_ASSIGNED) != 0)
|
||||||
|
{
|
||||||
|
/* Yes.. that that is the CPU we must use */
|
||||||
|
|
||||||
|
cpu = btcb->cpu;
|
||||||
|
rtcb = (FAR struct tcb_s *)g_assignedtasks[cpu].head;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint8_t minprio;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Find the CPU that is executing the lowest priority task (possibly its
|
/* Otherwise, find the CPU that is executing the lowest priority task
|
||||||
* IDLE task).
|
* (possibly its IDLE task).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
rtcb = NULL;
|
rtcb = NULL;
|
||||||
@ -190,18 +202,17 @@ bool sched_addreadytorun(FAR struct tcb_s *btcb)
|
|||||||
FAR struct tcb_s *candidate =
|
FAR struct tcb_s *candidate =
|
||||||
(FAR struct tcb_s *)g_assignedtasks[i].head;
|
(FAR struct tcb_s *)g_assignedtasks[i].head;
|
||||||
|
|
||||||
/* If this thread is executing its IDLE task, the use it. The IDLE
|
/* If this thread is executing its IDLE task, the use it. The
|
||||||
* task is always the last task in the assigned task list.
|
* IDLE task is always the last task in the assigned task list.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (candidate->flink == NULL)
|
if (candidate->flink == NULL)
|
||||||
{
|
{
|
||||||
/* The IDLE task should always be assigned to this CPU and have a
|
/* The IDLE task should always be assigned to this CPU and
|
||||||
* priority zero.
|
* have a priority of zero.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DEBUGASSERT((candidate->flags & TCB_FLAG_CPU_ASSIGNED) != 0 &&
|
DEBUGASSERT(candidate->sched_priority == 0);
|
||||||
candidate->sched_priority == 0);
|
|
||||||
|
|
||||||
rtcb = candidate;
|
rtcb = candidate;
|
||||||
cpu = i;
|
cpu = i;
|
||||||
@ -215,6 +226,7 @@ bool sched_addreadytorun(FAR struct tcb_s *btcb)
|
|||||||
cpu = i;
|
cpu = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Determine the desired new task state. First, if the new task priority
|
/* Determine the desired new task state. First, if the new task priority
|
||||||
* is higher then the priority of the lowest priority, running task, then
|
* is higher then the priority of the lowest priority, running task, then
|
||||||
@ -258,20 +270,46 @@ bool sched_addreadytorun(FAR struct tcb_s *btcb)
|
|||||||
btcb->task_state = TSTATE_TASK_PENDING;
|
btcb->task_state = TSTATE_TASK_PENDING;
|
||||||
doswitch = false;
|
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
|
/* Add the task to the list corresponding to the selected state
|
||||||
* and check if a context switch will occur
|
* 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);
|
switched = sched_addprioritized(btcb, tasklist);
|
||||||
|
|
||||||
/* If the selected task was the g_assignedtasks[] list, then a context
|
/* If the selected task was the g_assignedtasks[] list, then a context
|
||||||
* swith will occur.
|
* 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
|
/* The new btcb was added at the head of the ready-to-run list. It
|
||||||
* is now the new active task!
|
* is now the new active task!
|
||||||
@ -310,7 +348,7 @@ bool sched_addreadytorun(FAR struct tcb_s *btcb)
|
|||||||
* lifting machinery.
|
* lifting machinery.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
next = (FAR dq_queue_t *)btcb->flink;
|
next = (FAR struct tcb_s *)btcb->flink;
|
||||||
ASSERT(!rtcb->lockcount && next != NULL);
|
ASSERT(!rtcb->lockcount && next != NULL);
|
||||||
|
|
||||||
if ((btcb->flags & TCB_FLAG_CPU_ASSIGNED) != 0)
|
if ((btcb->flags & TCB_FLAG_CPU_ASSIGNED) != 0)
|
||||||
@ -328,22 +366,27 @@ bool sched_addreadytorun(FAR struct tcb_s *btcb)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
next->task_state = TSTATE_TASK_READYTORUN;
|
next->task_state = TSTATE_TASK_READYTORUN;
|
||||||
(void)sched_addprioritized(btcb, &g_readytorun);
|
(void)sched_addprioritized(btcb,
|
||||||
|
(FAR dq_queue_t *)&g_readytorun);
|
||||||
}
|
}
|
||||||
|
|
||||||
doswitch = true;
|
doswitch = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* The new btcb was added either (1) in the middle of the assigned
|
/* No context switch. Assign the CPU and set the assigned state */
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
DEBUGASSERT(task_state != TSTATE_TASK_RUNNING);
|
DEBUGASSERT(task_state == TSTATE_TASK_ASSIGNED);
|
||||||
|
|
||||||
btcb->task_state = TSTATE_TASK_READYTORUN;
|
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;
|
doswitch = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* sched/sched/sched_mergepending.c
|
* 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>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -55,13 +55,14 @@
|
|||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* This function merges the prioritized g_pendingtasks list into the
|
* This function merges the prioritized g_pendingtasks list into the
|
||||||
* prioritized g_readytorun task list.
|
* prioritized ready-to-run task list.
|
||||||
*
|
*
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* None
|
* None
|
||||||
*
|
*
|
||||||
* Return Value:
|
* 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:
|
* Assumptions:
|
||||||
* - The caller has established a critical section before
|
* - The caller has established a critical section before
|
||||||
@ -72,75 +73,82 @@
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CONFIG_SMP
|
||||||
bool sched_mergepending(void)
|
bool sched_mergepending(void)
|
||||||
{
|
{
|
||||||
FAR struct tcb_s *pndtcb;
|
FAR struct tcb_s *ptcb;
|
||||||
FAR struct tcb_s *pndnext;
|
FAR struct tcb_s *pnext;
|
||||||
FAR struct tcb_s *rtrtcb;
|
FAR struct tcb_s *rtcb;
|
||||||
FAR struct tcb_s *rtrprev;
|
FAR struct tcb_s *rprev;
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
/* Initialize the inner search loop */
|
/* Initialize the inner search loop */
|
||||||
|
|
||||||
rtrtcb = this_task();
|
rtcb = this_task();
|
||||||
|
|
||||||
/* Process every TCB in the g_pendingtasks list */
|
/* 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
|
/* REVISIT: Why don't we just remove the ptcb from pending task list
|
||||||
* new pndtcb. Each is list is maintained in ascending sched_priority
|
* 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.
|
* order.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (;
|
for (;
|
||||||
(rtrtcb && pndtcb->sched_priority <= rtrtcb->sched_priority);
|
(rtcb && ptcb->sched_priority <= rtcb->sched_priority);
|
||||||
rtrtcb = rtrtcb->flink);
|
rtcb = rtcb->flink);
|
||||||
|
|
||||||
/* Add the pndtcb to the spot found in the list. Check if the
|
/* Add the ptcb to the spot found in the list. Check if the
|
||||||
* pndtcb goes at the ends of the g_readytorun list. This would be
|
* 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
|
* 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;
|
rprev = rtcb->blink;
|
||||||
if (!rtrprev)
|
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 */
|
/* 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 */
|
/* Then insert at the head of the list */
|
||||||
|
|
||||||
pndtcb->flink = rtrtcb;
|
ptcb->flink = rtcb;
|
||||||
pndtcb->blink = NULL;
|
ptcb->blink = NULL;
|
||||||
rtrtcb->blink = pndtcb;
|
rtcb->blink = ptcb;
|
||||||
g_readytorun.head = (FAR dq_entry_t *)pndtcb;
|
g_readytorun.head = (FAR dq_entry_t *)ptcb;
|
||||||
rtrtcb->task_state = TSTATE_TASK_READYTORUN;
|
rtcb->task_state = TSTATE_TASK_READYTORUN;
|
||||||
pndtcb->task_state = TSTATE_TASK_RUNNING;
|
ptcb->task_state = TSTATE_TASK_RUNNING;
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Insert in the middle of the list */
|
/* Insert in the middle of the list */
|
||||||
|
|
||||||
pndtcb->flink = rtrtcb;
|
ptcb->flink = rtcb;
|
||||||
pndtcb->blink = rtrprev;
|
ptcb->blink = rprev;
|
||||||
rtrprev->flink = pndtcb;
|
rprev->flink = ptcb;
|
||||||
rtrtcb->blink = pndtcb;
|
rtcb->blink = ptcb;
|
||||||
pndtcb->task_state = TSTATE_TASK_READYTORUN;
|
ptcb->task_state = TSTATE_TASK_READYTORUN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set up for the next time through */
|
/* Set up for the next time through */
|
||||||
|
|
||||||
rtrtcb = pndtcb;
|
rtcb = ptcb;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark the input list empty */
|
/* Mark the input list empty */
|
||||||
@ -150,3 +158,48 @@ bool sched_mergepending(void)
|
|||||||
|
|
||||||
return ret;
|
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