revert between 56095 -> 55830 in arch
[AROS.git] / arch / arm-native / kernel / kernel_scheduler.c
blobfc8ccac31e0ab783be6eeece8c53feaf9cbfc7df
1 /*
2 Copyright © 2015-2018, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <exec/alerts.h>
7 #include <exec/execbase.h>
8 #include <exec/lists.h>
9 #include <proto/exec.h>
10 #include <proto/kernel.h>
12 //#include <kernel_base.h>
13 struct KernelBase;
14 #include <kernel_debug.h>
15 #include <kernel_scheduler.h>
17 #include "kernel_cpu.h"
19 #define AROS_NO_ATOMIC_OPERATIONS
20 #include <exec_platform.h>
22 #include <aros/types/spinlock_s.h>
24 #include <etask.h>
26 #undef bug
27 #include "exec_intern.h"
28 #undef bug
29 #include "kernel_intern.h"
31 #define DSCHED(x)
33 /* Check if the currently running task on this cpu should be rescheduled */
34 BOOL core_Schedule(void)
36 #if defined(DEBUG)
37 int cpunum = GetCPUNumber();
38 (void)cpunum;
39 #endif
40 struct Task *task = GET_THIS_TASK;
41 BOOL corereschedule = TRUE;
43 DSCHED(bug("[Kernel:%02d] core_Schedule()\n", cpunum));
45 FLAG_SCHEDSWITCH_CLEAR;
47 /* If task has pending exception, reschedule it so that the dispatcher may handle the exception */
48 if (!(task->tc_Flags & TF_EXCEPT))
50 #if defined(__AROSEXEC_SMP__)
51 KrnSpinLock(&PrivExecBase(SysBase)->TaskReadySpinLock, NULL,
52 SPINLOCK_MODE_READ);
53 #endif
54 /* Is the TaskReady empty? If yes, then the running task is the only one. Let it work */
55 if (IsListEmpty(&SysBase->TaskReady))
56 corereschedule = FALSE;
57 else
59 struct Task *nexttask;
60 #if defined(__AROSEXEC_SMP__)
61 int cpunum = GetCPUNumber();
62 uint32_t cpumask = (1 << cpunum);
63 #endif
65 If there are tasks ready for this cpu that have equal or lower priority,
66 and the current task has used its alloted time - reschedule so they can run
68 for (nexttask = (struct Task *)GetHead(&SysBase->TaskReady); nexttask != NULL; nexttask = (struct Task *)GetSucc(nexttask))
70 #if defined(__AROSEXEC_SMP__)
71 if ((GetIntETask(nexttask)->iet_CpuAffinity & cpumask) == cpumask)
73 #endif
74 if (nexttask->tc_Node.ln_Pri <= task->tc_Node.ln_Pri)
76 /* If the running task did not used it's whole quantum yet, let it work */
77 if (!FLAG_SCHEDQUANTUM_ISSET)
78 corereschedule = FALSE;
80 break;
81 #if defined(__AROSEXEC_SMP__)
83 #endif
86 #if defined(__AROSEXEC_SMP__)
87 KrnSpinUnLock(&PrivExecBase(SysBase)->TaskReadySpinLock);
88 #endif
91 DSCHED
93 if (corereschedule)
94 bug("[Kernel:%02d] '%s' @ 0x%p needs rescheduled ..\n", cpunum, task->tc_Node.ln_Name, task);
97 return corereschedule;
100 /* Switch the currently running task on this cpu to ready state */
101 void core_Switch(void)
103 #if defined(DEBUG)
104 int cpunum = GetCPUNumber();
105 #endif
106 struct Task *task = GET_THIS_TASK;
108 DSCHED(bug("[Kernel:%02d] core_Switch(%08x)\n", cpunum, task->tc_State));
110 if (task->tc_State == TS_RUN)
112 DSCHED(bug("[Kernel:%02d] Switching away from '%s' @ 0x%p\n", cpunum, task->tc_Node.ln_Name, task));
113 #if defined(__AROSEXEC_SMP__)
114 KrnSpinLock(&PrivExecBase(SysBase)->TaskRunningSpinLock, NULL,
115 SPINLOCK_MODE_WRITE);
116 Remove(&task->tc_Node);
117 KrnSpinUnLock(&PrivExecBase(SysBase)->TaskRunningSpinLock);
118 #endif
119 task->tc_State = TS_READY;
121 /* if the current task has gone out of stack bounds, suspend it to prevent further damage to the system */
122 if (task->tc_SPReg <= task->tc_SPLower || task->tc_SPReg > task->tc_SPUpper)
124 bug("[Kernel:%02d] '%s' @ 0x%p went out of stack limits\n", cpunum, task->tc_Node.ln_Name, task);
125 bug("[Kernel:%02d] - Lower 0x%p, upper 0x%p, SP 0x%p\n", cpunum, task->tc_SPLower, task->tc_SPUpper, task->tc_SPReg);
127 task->tc_SigWait = 0;
128 task->tc_State = TS_WAIT;
129 #if defined(__AROSEXEC_SMP__)
130 KrnSpinLock(&PrivExecBase(SysBase)->TaskWaitSpinLock, NULL,
131 SPINLOCK_MODE_WRITE);
132 #endif
133 Enqueue(&SysBase->TaskWait, &task->tc_Node);
134 #if defined(__AROSEXEC_SMP__)
135 KrnSpinUnLock(&PrivExecBase(SysBase)->TaskWaitSpinLock);
136 #endif
138 Alert(AN_StackProbe);
141 task->tc_IDNestCnt = IDNESTCOUNT_GET;
143 if (task->tc_Flags & TF_SWITCH)
144 AROS_UFC1NR(void, task->tc_Switch, AROS_UFCA(struct ExecBase *, SysBase, A6));
146 if (task->tc_State == TS_READY)
148 DSCHED(bug("[Kernel:%02d] Setting '%s' @ 0x%p as ready\n", cpunum, task->tc_Node.ln_Name, task));
149 #if defined(__AROSEXEC_SMP__)
150 KrnSpinLock(&PrivExecBase(SysBase)->TaskReadySpinLock, NULL,
151 SPINLOCK_MODE_WRITE);
152 #endif
153 Enqueue(&SysBase->TaskReady, &task->tc_Node);
154 #if defined(__AROSEXEC_SMP__)
155 KrnSpinUnLock(&PrivExecBase(SysBase)->TaskReadySpinLock);
156 #endif
161 /* Dispatch a "new" ready task on this cpu */
162 struct Task *core_Dispatch(void)
164 struct Task *newtask;
165 struct Task *task = GET_THIS_TASK;
166 #if defined(__AROSEXEC_SMP__) || defined(DEBUG)
167 int cpunum = GetCPUNumber();
168 (void)cpunum;
169 #endif
170 #if defined(__AROSEXEC_SMP__)
171 uint32_t cpumask = (1 << cpunum);
172 #endif
174 DSCHED(bug("[Kernel:%02d] core_Dispatch()\n", cpunum));
176 #if defined(__AROSEXEC_SMP__)
177 KrnSpinLock(&PrivExecBase(SysBase)->TaskReadySpinLock, NULL,
178 SPINLOCK_MODE_WRITE);
179 #endif
180 for (newtask = (struct Task *)GetHead(&SysBase->TaskReady); newtask != NULL; newtask = (struct Task *)GetSucc(newtask))
182 #if defined(__AROSEXEC_SMP__)
183 if ((GetIntETask(newtask)->iet_CpuAffinity & cpumask) == cpumask)
185 #endif
186 Remove(&newtask->tc_Node);
187 break;
188 #if defined(__AROSEXEC_SMP__)
190 #endif
192 #if defined(__AROSEXEC_SMP__)
193 KrnSpinUnLock(&PrivExecBase(SysBase)->TaskReadySpinLock);
194 #endif
196 if ((!newtask) && (task) && (task->tc_State != TS_WAIT))
197 newtask = task;
199 if (newtask != NULL)
201 if (newtask->tc_State == TS_READY || newtask->tc_State == TS_RUN)
203 DSCHED(bug("[Kernel:%02d] Preparing to run '%s' @ 0x%p\n",
204 cpunum, newtask->tc_Node.ln_Name, newtask));
206 SysBase->DispCount++;
207 IDNESTCOUNT_SET(newtask->tc_IDNestCnt);
208 SET_THIS_TASK(newtask);
209 SysBase->Elapsed = SysBase->Quantum;
210 FLAG_SCHEDQUANTUM_CLEAR;
212 /* Check the stack of the task we are about to launch. */
213 if ((newtask->tc_SPReg <= newtask->tc_SPLower) ||
214 (newtask->tc_SPReg > newtask->tc_SPUpper))
215 newtask->tc_State = TS_WAIT;
216 else
217 newtask->tc_State = TS_RUN;
220 BOOL launchtask = TRUE;
221 #if defined(__AROSEXEC_SMP__)
222 if (newtask->tc_State == TS_SPIN)
224 /* move it to the spinning list */
225 KrnSpinLock(&PrivExecBase(SysBase)->TaskSpinningLock, NULL,
226 SPINLOCK_MODE_WRITE);
227 AddHead(&PrivExecBase(SysBase)->TaskSpinning, &newtask->tc_Node);
228 KrnSpinUnLock(&PrivExecBase(SysBase)->TaskSpinningLock);
229 launchtask = FALSE;
231 #endif
232 if (newtask->tc_State == TS_WAIT)
234 #if defined(__AROSEXEC_SMP__)
235 KrnSpinLock(&PrivExecBase(SysBase)->TaskWaitSpinLock, NULL,
236 SPINLOCK_MODE_WRITE);
237 #endif
238 Enqueue(&SysBase->TaskWait, &task->tc_Node);
239 #if defined(__AROSEXEC_SMP__)
240 KrnSpinUnLock(&PrivExecBase(SysBase)->TaskWaitSpinLock);
241 #endif
242 launchtask = FALSE;
245 if (!launchtask)
247 /* if the new task shouldn't run - force a reschedule */
248 DSCHED(bug("[Kernel:%02d] Skipping '%s' @ 0x%p (state %08x)\n", cpunum, newtask->tc_Node.ln_Name, newtask, newtask->tc_State));
250 core_Switch();
251 newtask = core_Dispatch();
253 else
255 DSCHED(bug("[Kernel:%02d] Launching '%s' @ 0x%p (state %08x)\n", cpunum, newtask->tc_Node.ln_Name, newtask, newtask->tc_State));
258 else
260 /* Go idle if there is nothing to do */
261 DSCHED(bug("[Kernel:%02d] No ready Task(s) - entering sleep mode\n", cpunum));
264 * Idle counter is incremented every time when we enter here,
265 * not only once. This is correct.
267 SysBase->IdleCount++;
268 FLAG_SCHEDSWITCH_SET;
271 return newtask;