2 Copyright © 2015, The AROS Development Team. All rights reserved.
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 "kernel_cpu.h"
19 #define AROS_NO_ATOMIC_OPERATIONS
20 #include <exec_platform.h>
22 #include <aros/types/spinlock_s.h>
26 #include "exec_intern.h"
30 /* Check if the currently running task on this cpu should be rescheduled.. */
31 BOOL
core_Schedule(void)
34 int cpunum
= GetCPUNumber();
36 struct Task
*task
= GET_THIS_TASK
;
37 BOOL corereschedule
= TRUE
;
39 DSCHED(bug("[Kernel:%02d] core_Schedule()\n", cpunum
));
41 FLAG_SCHEDSWITCH_CLEAR
;
43 /* If task has pending exception, reschedule it so that the dispatcher may handle the exception */
44 if (!(task
->tc_Flags
& TF_EXCEPT
))
46 #if defined(__AROSEXEC_SMP__)
47 KrnSpinLock(&PrivExecBase(SysBase
)->TaskReadySpinLock
, NULL
,
50 /* Is the TaskReady empty? If yes, then the running task is the only one. Let it work */
51 if (IsListEmpty(&SysBase
->TaskReady
))
52 corereschedule
= FALSE
;
55 struct Task
*nexttask
;
56 #if defined(__AROSEXEC_SMP__)
57 int cpunum
= GetCPUNumber();
58 uint32_t cpumask
= (1 << cpunum
);
61 If there are tasks ready for this cpu that have equal or lower priority,
62 and the current task has used its alloted time - reschedule so they can run
64 for (nexttask
= (struct Task
*)GetHead(&SysBase
->TaskReady
); nexttask
!= NULL
; nexttask
= (struct Task
*)GetSucc(nexttask
))
66 #if defined(__AROSEXEC_SMP__)
67 if ((GetIntETask(nexttask
)->iet_CpuAffinity
& cpumask
) == cpumask
)
70 if (nexttask
->tc_Node
.ln_Pri
<= task
->tc_Node
.ln_Pri
)
72 /* If the running task did not used it's whole quantum yet, let it work */
73 if (!FLAG_SCHEDQUANTUM_ISSET
)
74 corereschedule
= FALSE
;
77 #if defined(__AROSEXEC_SMP__)
82 #if defined(__AROSEXEC_SMP__)
83 KrnSpinUnLock(&PrivExecBase(SysBase
)->TaskReadySpinLock
);
90 bug("[Kernel:%02d] '%s' @ 0x%p needs rescheduled ..\n", cpunum
, task
->tc_Node
.ln_Name
, task
);
93 return corereschedule
;
96 /* Switch the currently running task on this cpu to ready state */
97 void core_Switch(void)
100 int cpunum
= GetCPUNumber();
102 struct Task
*task
= GET_THIS_TASK
;
104 DSCHED(bug("[Kernel:%02d] core_Switch(%08x)\n", cpunum
, task
->tc_State
));
106 if (task
->tc_State
== TS_RUN
)
108 DSCHED(bug("[Kernel:%02d] Switching away from '%s' @ 0x%p\n", cpunum
, task
->tc_Node
.ln_Name
, task
));
109 #if defined(__AROSEXEC_SMP__)
110 KrnSpinLock(&PrivExecBase(SysBase
)->TaskRunningSpinLock
, NULL
,
111 SPINLOCK_MODE_WRITE
);
113 Remove(&task
->tc_Node
);
114 #if defined(__AROSEXEC_SMP__)
115 KrnSpinUnLock(&PrivExecBase(SysBase
)->TaskRunningSpinLock
);
117 task
->tc_State
= TS_READY
;
119 /* if the current task has gone out of stack bounds, suspend it to prevent further damage to the system */
120 if (task
->tc_SPReg
<= task
->tc_SPLower
|| task
->tc_SPReg
> task
->tc_SPUpper
)
122 bug("[Kernel:%02d] '%s' @ 0x%p went out of stack limits\n", cpunum
, task
->tc_Node
.ln_Name
, task
);
123 bug("[Kernel:%02d] - Lower 0x%p, upper 0x%p, SP 0x%p\n", cpunum
, task
->tc_SPLower
, task
->tc_SPUpper
, task
->tc_SPReg
);
125 task
->tc_SigWait
= 0;
126 task
->tc_State
= TS_WAIT
;
127 #if defined(__AROSEXEC_SMP__)
128 KrnSpinLock(&PrivExecBase(SysBase
)->TaskWaitSpinLock
, NULL
,
129 SPINLOCK_MODE_WRITE
);
131 Enqueue(&SysBase
->TaskWait
, &task
->tc_Node
);
132 #if defined(__AROSEXEC_SMP__)
133 KrnSpinUnLock(&PrivExecBase(SysBase
)->TaskWaitSpinLock
);
136 Alert(AN_StackProbe
);
139 task
->tc_IDNestCnt
= IDNESTCOUNT_GET
;
141 if (task
->tc_Flags
& TF_SWITCH
)
142 AROS_UFC1NR(void, task
->tc_Switch
, AROS_UFCA(struct ExecBase
*, SysBase
, A6
));
144 if (task
->tc_State
== TS_READY
)
146 DSCHED(bug("[Kernel:%02d] Setting '%s' @ 0x%p as ready\n", cpunum
, task
->tc_Node
.ln_Name
, task
));
147 #if defined(__AROSEXEC_SMP__)
148 KrnSpinLock(&PrivExecBase(SysBase
)->TaskReadySpinLock
, NULL
,
149 SPINLOCK_MODE_WRITE
);
151 Enqueue(&SysBase
->TaskReady
, &task
->tc_Node
);
152 #if defined(__AROSEXEC_SMP__)
153 KrnSpinUnLock(&PrivExecBase(SysBase
)->TaskReadySpinLock
);
159 /* Dispatch a "new" ready task on this cpu */
160 struct Task
*core_Dispatch(void)
162 struct Task
*newtask
;
163 struct Task
*task
= GET_THIS_TASK
;
164 #if defined(__AROSEXEC_SMP__) || defined(DEBUG)
165 int cpunum
= GetCPUNumber();
167 #if defined(__AROSEXEC_SMP__)
168 uint32_t cpumask
= (1 << cpunum
);
171 DSCHED(bug("[Kernel:%02d] core_Dispatch()\n", cpunum
));
173 #if defined(__AROSEXEC_SMP__)
174 KrnSpinLock(&PrivExecBase(SysBase
)->TaskReadySpinLock
, NULL
,
175 SPINLOCK_MODE_WRITE
);
177 for (newtask
= (struct Task
*)GetHead(&SysBase
->TaskReady
); newtask
!= NULL
; newtask
= (struct Task
*)GetSucc(newtask
))
179 #if defined(__AROSEXEC_SMP__)
180 if ((GetIntETask(newtask
)->iet_CpuAffinity
& cpumask
) == cpumask
)
183 Remove(&newtask
->tc_Node
);
185 #if defined(__AROSEXEC_SMP__)
189 #if defined(__AROSEXEC_SMP__)
190 KrnSpinUnLock(&PrivExecBase(SysBase
)->TaskReadySpinLock
);
193 if ((!newtask
) && (task
) && (task
->tc_State
!= TS_WAIT
))
197 (newtask
->tc_State
== TS_READY
) ||
198 (newtask
->tc_State
== TS_RUN
))
200 DSCHED(bug("[Kernel:%02d] Preparing to run '%s' @ 0x%p\n", cpunum
, newtask
->tc_Node
.ln_Name
, newtask
));
202 SysBase
->DispCount
++;
203 IDNESTCOUNT_SET(newtask
->tc_IDNestCnt
);
204 SET_THIS_TASK(newtask
);
205 SysBase
->Elapsed
= SysBase
->Quantum
;
206 FLAG_SCHEDQUANTUM_CLEAR
;
208 /* Check the stack of the task we are about to launch. */
209 if ((newtask
->tc_SPReg
<= newtask
->tc_SPLower
) ||
210 (newtask
->tc_SPReg
> newtask
->tc_SPUpper
))
211 newtask
->tc_State
= TS_WAIT
;
213 newtask
->tc_State
= TS_RUN
;
218 BOOL launchtask
= TRUE
;
219 #if defined(__AROSEXEC_SMP__)
220 if (newtask
->tc_State
== TS_SPIN
)
222 /* move it to the spinning list */
223 KrnSpinLock(&PrivExecBase(SysBase
)->TaskSpinningLock
, NULL
,
224 SPINLOCK_MODE_WRITE
);
225 AddHead(&PrivExecBase(SysBase
)->TaskSpinning
, &newtask
->tc_Node
);
226 KrnSpinUnLock(&PrivExecBase(SysBase
)->TaskSpinningLock
);
230 if (newtask
->tc_State
== TS_WAIT
)
232 #if defined(__AROSEXEC_SMP__)
233 KrnSpinLock(&PrivExecBase(SysBase
)->TaskWaitSpinLock
, NULL
,
234 SPINLOCK_MODE_WRITE
);
236 Enqueue(&SysBase
->TaskWait
, &task
->tc_Node
);
237 #if defined(__AROSEXEC_SMP__)
238 KrnSpinUnLock(&PrivExecBase(SysBase
)->TaskWaitSpinLock
);
245 /* if the new task shouldnt run - force a reschedule.. */
246 DSCHED(bug("[Kernel:%02d] Skipping '%s' @ 0x%p (state %08x)\n", cpunum
, newtask
->tc_Node
.ln_Name
, newtask
, newtask
->tc_State
));
249 newtask
= core_Dispatch();
253 DSCHED(bug("[Kernel:%02d] Launching '%s' @ 0x%p (state %08x)\n", cpunum
, newtask
->tc_Node
.ln_Name
, newtask
, newtask
->tc_State
));
258 /* Go idle if there is nothing to do ... */
259 DSCHED(bug("[Kernel:%02d] No ready Task(s) - entering sleep mode\n", cpunum
));
262 * Idle counter is incremented every time when we enter here,
263 * not only once. This is correct.
265 SysBase
->IdleCount
++;
266 FLAG_SCHEDSWITCH_SET
;