Skip to content

Commit 3619e61

Browse files
hujun260xiaoxiang781216
authored andcommitted
sched: adjust the scheduling strategy
1 Only the idle task can have the flag TCB_FLAG_CPU_LOCKED. According to the code logic, btcb cannot be an idle task, so this check can be removed. 2 Optimized the preemption logic check and removed the call to nxsched_add_prioritized. 3 Speed up the scheduling time while avoiding the potential for tasks to be moved multiple times between g_assignedtasks and g_readytorun. Configuring NuttX and compile: $ ./tools/configure.sh -l qemu-armv8a:nsh_smp $ make Running with qemu $ qemu-system-aarch64 -cpu cortex-a53 -smp 4 -nographic \ -machine virt,virtualization=on,gic-version=3 \ -net none -chardev stdio,id=con,mux=on -serial chardev:con \ -mon chardev=con,mode=readline -kernel ./nuttx Signed-off-by: hujun5 <[email protected]>
1 parent eb9030c commit 3619e61

File tree

3 files changed

+140
-124
lines changed

3 files changed

+140
-124
lines changed

sched/sched/queue.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/****************************************************************************
2+
* sched/sched/queue.h
3+
*
4+
* Licensed to the Apache Software Foundation (ASF) under one or more
5+
* contributor license agreements. See the NOTICE file distributed with
6+
* this work for additional information regarding copyright ownership. The
7+
* ASF licenses this file to you under the Apache License, Version 2.0 (the
8+
* "License"); you may not use this file except in compliance with the
9+
* License. You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16+
* License for the specific language governing permissions and limitations
17+
* under the License.
18+
*
19+
****************************************************************************/
20+
21+
#ifndef __INCLUDE_SCHED_SCHED_NUTTX_QUEUE_H
22+
#define __INCLUDE_SCHED_SCHED_NUTTX_QUEUE_H
23+
24+
/****************************************************************************
25+
* Included Files
26+
****************************************************************************/
27+
28+
#include <nuttx/queue.h>
29+
30+
/****************************************************************************
31+
* Pre-processor Definitions
32+
****************************************************************************/
33+
34+
#define dq_addfirst_nonempty(p, q) \
35+
do \
36+
{ \
37+
FAR dq_entry_t *tmp_node = (p); \
38+
tmp_node->blink = NULL; \
39+
tmp_node->flink = (q)->head; \
40+
(q)->head->blink = tmp_node; \
41+
(q)->head = tmp_node; \
42+
} \
43+
while (0)
44+
45+
#define dq_rem_head(p, q) \
46+
do \
47+
{ \
48+
FAR dq_entry_t *tmp_node = (p); \
49+
FAR dq_entry_t *tmp_next = tmp_node->flink; \
50+
(q)->head = tmp_next; \
51+
tmp_next->blink = NULL; \
52+
tmp_node->flink = NULL; \
53+
} \
54+
while (0)
55+
56+
#define dq_rem_mid(p) \
57+
do \
58+
{ \
59+
FAR dq_entry_t *tmp_prev = (FAR dq_entry_t *)p->blink; \
60+
FAR dq_entry_t *tmp_next = (FAR dq_entry_t *)p->flink; \
61+
tmp_prev->flink = tmp_next; \
62+
tmp_next->blink = tmp_prev; \
63+
} \
64+
while (0)
65+
66+
#endif /* __INCLUDE_NUTTX_QUEUE_H_ */

sched/sched/sched_addreadytorun.c

Lines changed: 30 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@
2929
#include <stdbool.h>
3030
#include <assert.h>
3131

32-
#include <nuttx/queue.h>
33-
3432
#include "irq/irq.h"
33+
#include "sched/queue.h"
3534
#include "sched/sched.h"
3635

3736
/****************************************************************************
@@ -154,30 +153,14 @@ bool nxsched_add_readytorun(FAR struct tcb_s *btcb)
154153
bool nxsched_add_readytorun(FAR struct tcb_s *btcb)
155154
{
156155
FAR struct tcb_s *rtcb;
156+
FAR struct tcb_s *headtcb;
157157
FAR dq_queue_t *tasklist;
158158
bool doswitch;
159159
int task_state;
160160
int cpu;
161161
int me;
162162

163-
/* Check if the blocked TCB is locked to this CPU */
164-
165-
if ((btcb->flags & TCB_FLAG_CPU_LOCKED) != 0)
166-
{
167-
/* Yes.. that is the CPU we must use */
168-
169-
task_state = TSTATE_TASK_ASSIGNED;
170-
cpu = btcb->cpu;
171-
}
172-
else
173-
{
174-
/* Otherwise, find the CPU that is executing the lowest priority task
175-
* (possibly its IDLE task).
176-
*/
177-
178-
task_state = TSTATE_TASK_READYTORUN;
179-
cpu = nxsched_select_cpu(btcb->affinity);
180-
}
163+
cpu = nxsched_select_cpu(btcb->affinity);
181164

182165
/* Get the task currently running on the CPU (may be the IDLE task) */
183166

@@ -193,6 +176,10 @@ bool nxsched_add_readytorun(FAR struct tcb_s *btcb)
193176
{
194177
task_state = TSTATE_TASK_RUNNING;
195178
}
179+
else
180+
{
181+
task_state = TSTATE_TASK_READYTORUN;
182+
}
196183

197184
/* If the selected state is TSTATE_TASK_RUNNING, then we would like to
198185
* start running the task. Be we cannot do that if pre-emption is
@@ -207,8 +194,7 @@ bool nxsched_add_readytorun(FAR struct tcb_s *btcb)
207194
* situation.
208195
*/
209196

210-
if ((nxsched_islocked_global()) &&
211-
task_state != TSTATE_TASK_ASSIGNED)
197+
if (nxsched_islocked_global())
212198
{
213199
/* Add the new ready-to-run task to the g_pendingtasks task list for
214200
* now.
@@ -233,7 +219,7 @@ bool nxsched_add_readytorun(FAR struct tcb_s *btcb)
233219
btcb->task_state = TSTATE_TASK_READYTORUN;
234220
doswitch = false;
235221
}
236-
else /* (task_state == TSTATE_TASK_ASSIGNED || task_state == TSTATE_TASK_RUNNING) */
222+
else /* (task_state == TSTATE_TASK_RUNNING) */
237223
{
238224
/* If we are modifying some assigned task list other than our own, we
239225
* will need to stop that CPU.
@@ -245,109 +231,32 @@ bool nxsched_add_readytorun(FAR struct tcb_s *btcb)
245231
DEBUGVERIFY(up_cpu_pause(cpu));
246232
}
247233

248-
/* Add the task to the list corresponding to the selected state
249-
* and check if a context switch will occur
250-
*/
234+
tasklist = &g_assignedtasks[cpu];
235+
236+
/* Change "head" from TSTATE_TASK_RUNNING to TSTATE_TASK_ASSIGNED */
251237

252-
tasklist = list_assignedtasks(cpu);
253-
doswitch = nxsched_add_prioritized(btcb, tasklist);
238+
headtcb = (FAR struct tcb_s *)tasklist->head;
239+
DEBUGASSERT(headtcb->task_state = TSTATE_TASK_RUNNING);
240+
headtcb->task_state = TSTATE_TASK_ASSIGNED;
254241

255-
/* If the selected task list was the g_assignedtasks[] list and if the
256-
* new tasks is the highest priority (RUNNING) task, then a context
257-
* switch will occur.
242+
/* Add btcb to the head of the g_assignedtasks
243+
* task list and mark it as running
258244
*/
259245

260-
if (doswitch)
261-
{
262-
FAR struct tcb_s *next;
263-
264-
/* The new btcb was added at the head of the ready-to-run list. It
265-
* is now the new active task!
266-
*/
267-
268-
/* Assign the CPU and set the running state */
269-
270-
DEBUGASSERT(task_state == TSTATE_TASK_RUNNING);
271-
272-
btcb->cpu = cpu;
273-
btcb->task_state = TSTATE_TASK_RUNNING;
274-
275-
/* Adjust global pre-emption controls. If the lockcount is
276-
* greater than zero, then this task/this CPU holds the scheduler
277-
* lock.
278-
*/
279-
280-
if (btcb->lockcount > 0)
281-
{
282-
g_cpu_lockset |= (1 << cpu);
283-
}
284-
else
285-
{
286-
g_cpu_lockset &= ~(1 << cpu);
287-
}
288-
289-
/* NOTE: If the task runs on another CPU(cpu), adjusting global IRQ
290-
* controls will be done in the pause handler on the new CPU(cpu).
291-
* If the task is scheduled on this CPU(me), do nothing because
292-
* this CPU already has a critical section
293-
*/
294-
295-
/* If the following task is not locked to this CPU, then it must
296-
* be moved to the g_readytorun list. Since it cannot be at the
297-
* head of the list, we can do this without invoking any heavy
298-
* lifting machinery.
299-
*/
300-
301-
DEBUGASSERT(btcb->flink != NULL);
302-
next = btcb->flink;
303-
304-
if ((next->flags & TCB_FLAG_CPU_LOCKED) != 0)
305-
{
306-
DEBUGASSERT(next->cpu == cpu);
307-
next->task_state = TSTATE_TASK_ASSIGNED;
308-
}
309-
else
310-
{
311-
/* Remove the task from the assigned task list */
312-
313-
dq_rem((FAR dq_entry_t *)next, tasklist);
314-
315-
/* Add the task to the g_readytorun or to the g_pendingtasks
316-
* list. NOTE: That the above operations may cause the
317-
* scheduler to become locked. It may be assigned to a
318-
* different CPU the next time that it runs.
319-
*/
320-
321-
if (nxsched_islocked_global())
322-
{
323-
next->task_state = TSTATE_TASK_PENDING;
324-
tasklist = list_pendingtasks();
325-
}
326-
else
327-
{
328-
next->task_state = TSTATE_TASK_READYTORUN;
329-
tasklist = list_readytorun();
330-
}
331-
332-
nxsched_add_prioritized(next, tasklist);
333-
}
334-
}
335-
else
246+
dq_addfirst_nonempty((FAR dq_entry_t *)btcb, tasklist);
247+
248+
DEBUGASSERT(task_state == TSTATE_TASK_RUNNING);
249+
btcb->cpu = cpu;
250+
btcb->task_state = TSTATE_TASK_RUNNING;
251+
252+
doswitch = true;
253+
254+
/* Resume scheduling lock */
255+
256+
DEBUGASSERT(g_cpu_lockset == 0);
257+
if (btcb->lockcount > 0)
336258
{
337-
/* No context switch. Assign the CPU and set the assigned state.
338-
*
339-
* REVISIT: I have seen this assertion fire. Apparently another
340-
* CPU may add another, higher priority task to the same
341-
* g_assignedtasks[] list sometime after nxsched_select_cpu() was
342-
* called above, leaving this TCB in the wrong task list if
343-
* task_state is TSTATE_TASK_ASSIGNED).
344-
*/
345-
346-
DEBUGASSERT(task_state == TSTATE_TASK_ASSIGNED);
347-
348-
btcb->cpu = cpu;
349-
btcb->task_state = TSTATE_TASK_ASSIGNED;
350-
doswitch = false;
259+
g_cpu_lockset |= (1 << cpu);
351260
}
352261

353262
/* All done, restart the other CPU (if it was paused). */

sched/sched/sched_removereadytorun.c

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@
2929
#include <stdbool.h>
3030
#include <assert.h>
3131

32-
#include <nuttx/queue.h>
3332
#include <nuttx/sched_note.h>
3433

3534
#include "irq/irq.h"
35+
#include "sched/queue.h"
3636
#include "sched/sched.h"
3737

3838
/****************************************************************************
@@ -190,7 +190,48 @@ bool nxsched_remove_readytorun(FAR struct tcb_s *rtcb, bool merge)
190190
* or the g_assignedtasks[cpu] list.
191191
*/
192192

193-
dq_rem((FAR dq_entry_t *)rtcb, tasklist);
193+
dq_rem_head((FAR dq_entry_t *)rtcb, tasklist);
194+
195+
/* Find the highest priority non-running tasks in the g_assignedtasks
196+
* list of other CPUs, and also non-idle tasks, place them in the
197+
* g_readytorun list. so as to find the task with the highest priority,
198+
* globally
199+
*/
200+
201+
for (int i = 0; i < CONFIG_SMP_NCPUS; i++)
202+
{
203+
if (i == cpu)
204+
{
205+
/* The highest priority task of the current
206+
* CPU has been found, which is nxttcb.
207+
*/
208+
209+
continue;
210+
}
211+
212+
for (rtrtcb = (FAR struct tcb_s *)g_assignedtasks[i].head;
213+
!is_idle_task(rtrtcb); rtrtcb = rtrtcb->flink)
214+
{
215+
if (rtrtcb->task_state != TSTATE_TASK_RUNNING &&
216+
CPU_ISSET(cpu, &rtrtcb->affinity))
217+
{
218+
/* We have found the task with the highest priority whose
219+
* CPU index is i. Since this task must be between the two
220+
* tasks, we can use the dq_rem_mid macro to delete it.
221+
*/
222+
223+
dq_rem_mid(rtrtcb);
224+
rtrtcb->task_state = TSTATE_TASK_READYTORUN;
225+
226+
/* Add rtrtcb to g_readytorun to find
227+
* the task with the highest global priority
228+
*/
229+
230+
nxsched_add_prioritized(rtrtcb, &g_readytorun);
231+
break;
232+
}
233+
}
234+
}
194235

195236
/* Which task will go at the head of the list? It will be either the
196237
* next tcb in the assigned task list (nxttcb) or a TCB in the
@@ -221,7 +262,7 @@ bool nxsched_remove_readytorun(FAR struct tcb_s *rtcb, bool merge)
221262
*/
222263

223264
dq_rem((FAR dq_entry_t *)rtrtcb, list_readytorun());
224-
dq_addfirst((FAR dq_entry_t *)rtrtcb, tasklist);
265+
dq_addfirst_nonempty((FAR dq_entry_t *)rtrtcb, tasklist);
225266

226267
rtrtcb->cpu = cpu;
227268
nxttcb = rtrtcb;

0 commit comments

Comments
 (0)