add the task to the head instead of en-queueing, since it is faster
[AROS.git] / arch / arm-native / kernel / kernel_scheduler.c
blob3162f1172f346df3ba5c02161c8cbed474b4f06b
1 /*
2 Copyright © 2015, The AROS Development Team. All rights reserved.
3 $Id$
5 */
7 #include <exec/alerts.h>
8 #include <exec/execbase.h>
9 #include <exec/lists.h>
10 #include <proto/exec.h>
11 #include <proto/kernel.h>
13 //#include <kernel_base.h>
14 #include <kernel_debug.h>
15 #include <kernel_scheduler.h>
17 #include <exec_platform.h>
19 #include <aros/types/spinlock_s.h>
21 #include <etask.h>
23 #include "exec_intern.h"
25 #define D(x)
28 * Schedule the currently running task away. Put it into the TaskReady list
29 * in some smart way. This function is subject of change and it will be probably replaced
30 * by some plugin system in the future
32 BOOL core_Schedule(void)
34 struct Task *task = GET_THIS_TASK;
36 D(bug("[KRN:BCM2708] core_Schedule()\n"));
38 SysBase->AttnResched &= ~ARF_AttnSwitch;
40 /* If task has pending exception, reschedule it so that the dispatcher may handle the exception */
41 if (!(task->tc_Flags & TF_EXCEPT))
43 BYTE pri;
45 /* Is the TaskReady empty? If yes, then the running task is the only one. Let it work */
46 if (IsListEmpty(&SysBase->TaskReady))
47 return FALSE;
49 #if defined(__AROSEXEC_SMP__)
50 KrnSpinLock(&PrivExecBase(SysBase)->TaskReadySpinLock, SPINLOCK_MODE_READ);
51 #endif
52 /* Does the TaskReady list contains tasks with priority equal or lower than current task?
53 * If so, then check further... */
54 pri = ((struct Task*)GetHead(&SysBase->TaskReady))->tc_Node.ln_Pri;
55 if (pri <= task->tc_Node.ln_Pri)
57 /* If the running task did not used it's whole quantum yet, let it work */
58 if (!(SysBase->SysFlags & SFF_QuantumOver))
60 #if defined(__AROSEXEC_SMP__)
61 KrnSpinUnLock(&PrivExecBase(SysBase)->TaskReadySpinLock);
62 #endif
63 return FALSE;
66 #if defined(__AROSEXEC_SMP__)
67 KrnSpinUnLock(&PrivExecBase(SysBase)->TaskReadySpinLock);
68 #endif
71 /*
72 * If we got here, then the rescheduling is necessary.
73 * Put the task into the TaskReady list.
75 D(bug("[KRN:BCM2708] Setting task 0x%p (%s) to READY\n", task, task->tc_Node.ln_Name));
76 #if defined(__AROSEXEC_SMP__)
77 KrnSpinLock(&PrivExecBase(SysBase)->TaskRunningSpinLock, SPINLOCK_MODE_WRITE);
78 Remove(&task->tc_Node);
79 KrnSpinUnLock(&PrivExecBase(SysBase)->TaskRunningSpinLock);
80 #endif
81 task->tc_State = TS_READY;
82 #if defined(__AROSEXEC_SMP__)
83 KrnSpinLock(&PrivExecBase(SysBase)->TaskReadySpinLock, SPINLOCK_MODE_WRITE);
84 #endif
85 Enqueue(&SysBase->TaskReady, &task->tc_Node);
86 #if defined(__AROSEXEC_SMP__)
87 KrnSpinUnLock(&PrivExecBase(SysBase)->TaskReadySpinLock);
88 #endif
90 /* Select new task to run */
91 return TRUE;
94 /* Actually switch away from the task */
95 void core_Switch(void)
97 struct Task *task = GET_THIS_TASK;
99 D(bug("[KRN:BCM2708] core_Switch(): Old task = %p (%s)\n", task, task->tc_Node.ln_Name));
101 if (task->tc_SPReg <= task->tc_SPLower || task->tc_SPReg > task->tc_SPUpper)
103 bug("[KRN:BCM2708] Task %s went out of stack limits\n", task->tc_Node.ln_Name);
104 bug("[KRN:BCM2708] Lower %p, upper %p, SP %p\n", task->tc_SPLower, task->tc_SPUpper, task->tc_SPReg);
106 * Suspend the task to stop it from causing more harm. In some rare cases, if the task is holding
107 * lock on some global/library semaphore it will most likelly mean immenent freeze. In most cases
108 * however, user will be shown an alert.
110 #if defined(__AROSEXEC_SMP__)
111 KrnSpinLock(&PrivExecBase(SysBase)->TaskRunningSpinLock, SPINLOCK_MODE_WRITE);
112 #endif
113 Remove(&task->tc_Node);
114 #if defined(__AROSEXEC_SMP__)
115 KrnSpinUnLock(&PrivExecBase(SysBase)->TaskRunningSpinLock);
116 #endif
118 task->tc_SigWait = 0;
119 task->tc_State = TS_WAIT;
120 Enqueue(&SysBase->TaskWait, &task->tc_Node);
122 Alert(AN_StackProbe);
125 task->tc_IDNestCnt = SysBase->IDNestCnt;
127 if (task->tc_Flags & TF_SWITCH)
128 AROS_UFC1NR(void, task->tc_Switch, AROS_UFCA(struct ExecBase *, SysBase, A6));
132 * Task dispatcher. Basically it may be the same one no matter
133 * what scheduling algorithm is used (except SysBase->Elapsed reloading)
135 struct Task *core_Dispatch(void)
137 struct Task *task;
138 uint32_t cpumask;
139 uint32_t tmp;
141 D(bug("[KRN:BCM2708] core_Dispatch()\n"));
143 asm volatile (" mrc p15, 0, %0, c0, c0, 5 " : "=r" (tmp));
144 cpumask = (1 << (tmp & 3));
146 #if defined(__AROSEXEC_SMP__)
147 KrnSpinLock(&PrivExecBase(SysBase)->TaskReadySpinLock, SPINLOCK_MODE_WRITE);
148 #endif
149 for (task = (struct Task *)GetHead(&SysBase->TaskReady); task != NULL; task = (struct Task *)GetSucc(task))
151 #if defined(__AROSEXEC_SMP__)
152 if ((GetIntETask(task)->iet_CpuAffinity & cpumask) == cpumask)
154 #endif
155 Remove(&task->tc_Node);
156 break;
157 #if defined(__AROSEXEC_SMP__)
159 #endif
161 #if defined(__AROSEXEC_SMP__)
162 KrnSpinUnLock(&PrivExecBase(SysBase)->TaskReadySpinLock);
163 #endif
165 if (!task)
167 /* Is the list of ready tasks empty? Well, go idle. */
168 D(bug("[KRN:BCM2708] No ready tasks, entering sleep mode\n"));
171 * Idle counter is incremented every time when we enter here,
172 * not only once. This is correct.
174 SysBase->IdleCount++;
175 SysBase->AttnResched |= ARF_AttnSwitch;
177 return NULL;
180 SysBase->DispCount++;
181 SysBase->IDNestCnt = task->tc_IDNestCnt;
182 #if defined(__AROSEXEC_SMP__)
183 KrnSpinLock(&PrivExecBase(SysBase)->TaskRunningSpinLock, SPINLOCK_MODE_WRITE);
184 AddHead(&PrivExecBase(SysBase)->TaskRunning, &task->tc_Node);
185 KrnSpinUnLock(&PrivExecBase(SysBase)->TaskRunningSpinLock);
186 #endif
187 SET_THIS_TASK(task);
188 SysBase->Elapsed = SysBase->Quantum;
189 SysBase->SysFlags &= ~SFF_QuantumOver;
190 task->tc_State = TS_RUN;
192 D(bug("[KRN:BCM2708] New task = %p (%s)\n", task, task->tc_Node.ln_Name));
194 /* Check the stack of the task we are about to launch. */
196 if (task->tc_SPReg <= task->tc_SPLower || task->tc_SPReg > task->tc_SPUpper)
198 /* Don't let the task run, switch it away (raising Alert) and dispatch another task */
199 core_Switch();
200 return core_Dispatch();
203 if (task->tc_Flags & TF_LAUNCH)
204 AROS_UFC1NR(void, task->tc_Launch, AROS_UFCA(struct ExecBase *, SysBase, A6));
206 /* Leave interrupt and jump to the new task */
207 return task;