revert between 56095 -> 55830 in arch
[AROS.git] / rom / kernel / kernel_scheduler.c
blob852f9c36a2814f7cf0cd507dea19c2e282a250e4
1 /*
2 Copyright © 1995-2018, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc:
6 */
8 #include <exec/alerts.h>
9 #include <exec/execbase.h>
10 #include <proto/exec.h>
12 #include <kernel_base.h>
13 #include <kernel_debug.h>
14 #include <kernel_scheduler.h>
16 #define AROS_NO_ATOMIC_OPERATIONS
17 #include "exec_platform.h"
19 #define D(x)
22 * Schedule the currently running task away. Put it into the TaskReady list
23 * in some smart way. This function is subject of change and it will be probably replaced
24 * by some plugin system in the future
26 BOOL core_Schedule(void)
28 struct Task *task = GET_THIS_TASK;
30 D(bug("[KRN] core_Schedule()\n"));
32 FLAG_SCHEDSWITCH_CLEAR;
34 if (task->tc_State == TS_REMOVED)
35 return FALSE;
37 /* If task has pending exception, reschedule it so that the dispatcher may handle the exception */
38 if (!(task->tc_Flags & TF_EXCEPT))
40 BYTE pri;
42 /* Is the TaskReady empty? If yes, then the running task is the only one. Let it work */
43 if (IsListEmpty(&SysBase->TaskReady))
44 return FALSE;
46 /* Does the TaskReady list contain tasks with priority equal to or lower than current task?
47 * If so, then check further... */
48 pri = ((struct Task*)GetHead(&SysBase->TaskReady))->tc_Node.ln_Pri;
49 if (pri <= task->tc_Node.ln_Pri)
51 /* If the running task did not used it's whole quantum yet, let it work */
52 if (!FLAG_SCHEDQUANTUM_ISSET)
53 return FALSE;
57 D(bug("[KRN] Rescheduling required\n"));
59 /* Select new task to run */
60 return TRUE;
63 /* Actually switch away from the task */
64 void core_Switch(void)
66 struct Task *task = GET_THIS_TASK;
67 ULONG showAlert = 0;
69 D(bug("[KRN] core_Switch(): Old task = %p (%s)\n", task, task->tc_Node.ln_Name));
71 if (task->tc_State != TS_RUN)
72 Remove(&task->tc_Node);
74 if ((task->tc_State != TS_WAIT) && (task->tc_State != TS_REMOVED))
75 task->tc_State = TS_READY;
77 #ifndef __mc68000
78 if (task->tc_SPReg <= task->tc_SPLower || task->tc_SPReg > task->tc_SPUpper)
80 bug("[KRN] Task %s went out of stack limits\n", task->tc_Node.ln_Name);
81 bug("[KRN] Lower %p, upper %p, SP %p\n", task->tc_SPLower, task->tc_SPUpper, task->tc_SPReg);
83 * Suspend the task to stop it from causing more harm. In some rare cases, if the task is holding
84 * lock on some global/library semaphore it will most likelly mean immenent freeze. In most cases
85 * however, user will be shown an alert.
87 task->tc_SigWait = 0;
88 task->tc_State = TS_WAIT;
90 showAlert = AN_StackProbe;
92 #endif
94 task->tc_IDNestCnt = IDNESTCOUNT_GET;
96 if (task->tc_State == TS_READY)
98 if (task->tc_Flags & TF_SWITCH)
99 AROS_UFC1NR(void, task->tc_Switch, AROS_UFCA(struct ExecBase *, SysBase, A6));
100 Enqueue(&SysBase->TaskReady, &task->tc_Node);
102 else if (task->tc_State != TS_REMOVED)
104 D(bug("[KRN] Setting '%s' @ 0x%p to wait\n", task->tc_Node.ln_Name, task));
105 Enqueue(&SysBase->TaskWait, &task->tc_Node);
107 if (showAlert)
108 Alert(showAlert);
112 * Task dispatcher. Basically it may be the same one no matter
113 * what scheduling algorithm is used (except SysBase->Elapsed reloading)
115 struct Task *core_Dispatch(void)
117 struct Task *task;
119 D(bug("[KRN] core_Dispatch()\n"));
121 task = (struct Task *)REMHEAD(&SysBase->TaskReady);
122 if (!task)
124 /* Is the list of ready tasks empty? Well, go idle. */
125 D(bug("[KRN] No ready tasks, entering sleep mode\n"));
128 * Idle counter is incremented every time when we enter here,
129 * not only once. This is correct.
131 SysBase->IdleCount++;
132 FLAG_SCHEDSWITCH_SET;
134 return NULL;
137 if (task->tc_State == TS_READY)
139 IDNESTCOUNT_SET(task->tc_IDNestCnt);
140 SET_THIS_TASK(task);
141 SCHEDELAPSED_SET(SCHEDQUANTUM_GET);
142 FLAG_SCHEDQUANTUM_CLEAR;
144 * Check the stack of the task we are about to launch.
145 * Unfortunately original m68k programs can change stack manually without updating SPLower or SPUpper.
146 * For example WB3.1 C:SetPatch adds exec/OpenDevice() patch that swaps stacks manually.
147 * Result is that _all_ programs that call OpenDevice() crash if stack is checked.
149 #ifndef __mc68000
150 if (task->tc_SPReg <= task->tc_SPLower || task->tc_SPReg > task->tc_SPUpper)
151 task->tc_State = TS_WAIT;
152 else
153 #endif
154 task->tc_State = TS_RUN;
157 if (task->tc_State != TS_RUN)
159 D(bug("[KRN] Skipping '%s' @ 0x%p (state %08x)\n", task->tc_Node.ln_Name, task, task->tc_State));
161 core_Switch();
162 task = core_Dispatch();
164 else
166 D(bug("[KRN] New task = %p (%s)\n", task, task->tc_Node.ln_Name));
168 SysBase->DispCount++;
169 if (task->tc_Flags & TF_LAUNCH)
170 AROS_UFC1NR(void, task->tc_Launch, AROS_UFCA(struct ExecBase *, SysBase, A6));
173 /* Leave interrupt and jump to the new task */
174 return task;