1 #include <exec/alerts.h>
2 #include <exec/execbase.h>
3 #include <proto/exec.h>
5 #include <kernel_base.h>
6 #include <kernel_debug.h>
7 #include <kernel_scheduler.h>
9 /* FIXME: Can we remove usage of exec_intern.h ? */
10 #include "exec_intern.h"
15 * Schedule the currently running task away. Put it into the TaskReady list
16 * in some smart way. This function is subject of change and it will be probably replaced
17 * by some plugin system in the future
19 BOOL
core_Schedule(void)
21 struct Task
*task
= SysBase
->ThisTask
;
23 D(bug("[KRN] core_Schedule()\n"));
25 SysBase
->AttnResched
&= ~ARF_AttnSwitch
;
27 /* If task has pending exception, reschedule it so that the dispatcher may handle the exception */
28 if (!(task
->tc_Flags
& TF_EXCEPT
))
32 /* Is the TaskReady empty? If yes, then the running task is the only one. Let it work */
33 if (IsListEmpty(&SysBase
->TaskReady
))
36 /* Does the TaskReady list contains tasks with priority equal or lower than current task?
37 * If so, then check further... */
38 pri
= ((struct Task
*)GetHead(&SysBase
->TaskReady
))->tc_Node
.ln_Pri
;
39 if (pri
<= task
->tc_Node
.ln_Pri
)
41 /* If the running task did not used it's whole quantum yet, let it work */
42 if (!(SysBase
->SysFlags
& SFF_QuantumOver
))
48 * If we got here, then the rescheduling is necessary.
49 * Put the task into the TaskReady list.
51 D(bug("[KRN] Setting task 0x%p (%s) to READY\n", task
, task
->tc_Node
.ln_Name
));
52 task
->tc_State
= TS_READY
;
53 Enqueue(&SysBase
->TaskReady
, &task
->tc_Node
);
55 /* Select new task to run */
59 /* Actually switch away from the task */
60 void core_Switch(void)
62 struct Task
*task
= SysBase
->ThisTask
;
64 D(bug("[KRN] core_Switch(): Old task = %p (%s)\n", task
, task
->tc_Node
.ln_Name
));
66 task
->tc_IDNestCnt
= SysBase
->IDNestCnt
;
68 if (task
->tc_Flags
& TF_SWITCH
)
69 AROS_UFC1(void, task
->tc_Switch
, AROS_UFCA(struct ExecBase
*, SysBase
, A6
));
73 * Task dispatcher. Basically it may be the same one no matter
74 * what scheduling algorithm is used (except SysBase->Elapsed reloading)
76 struct Task
*core_Dispatch(void)
80 D(bug("[KRN] core_Dispatch()\n"));
82 task
= (struct Task
*)REMHEAD(&SysBase
->TaskReady
);
85 /* Is the list of ready tasks empty? Well, go idle. */
86 D(bug("[KRN] No ready tasks, entering sleep mode\n"));
88 /* Idle counter is incremented every time when we enter here,
89 not only once. This is correct. */
91 SysBase
->AttnResched
|= ARF_AttnSwitch
;
98 SysBase
->IDNestCnt
= task
->tc_IDNestCnt
;
99 SysBase
->ThisTask
= task
;
100 SysBase
->Elapsed
= SysBase
->Quantum
;
101 SysBase
->SysFlags
&= ~SFF_QuantumOver
;
102 task
->tc_State
= TS_RUN
;
104 D(bug("[KRN] New task = %p (%s)\n", task
, task
->tc_Node
.ln_Name
));
107 * Increase TaskStorage if it is not big enough
109 struct ETask
*etask
= task
->tc_UnionETask
.tc_ETask
;
110 if ((int)etask
->et_TaskStorage
[0] < PrivExecBase(SysBase
)->TaskStorageSize
)
112 IPTR
*oldstorage
= etask
->et_TaskStorage
;
113 ULONG oldsize
= (ULONG
)oldstorage
[0];
115 etask
->et_TaskStorage
= AllocMem(PrivExecBase(SysBase
)->TaskStorageSize
, MEMF_PUBLIC
|MEMF_CLEAR
);
116 /* FIXME: Add fault handling */
118 CopyMem(oldstorage
, etask
->et_TaskStorage
, oldsize
);
119 FreeMem(oldstorage
, oldsize
);
123 * Check the stack of the task we are about to launch.
124 * Unfortunately original m68k programs can change stack manually without updating SPLower or SPUpper.
125 * For example WB3.1 C:SetPatch adds exec/OpenDevice() patch that swaps stacks manually.
126 * Result is that _all_ programs that call OpenDevice() crash if stack is checked.
129 if (task
->tc_SPReg
<= task
->tc_SPLower
|| task
->tc_SPReg
> task
->tc_SPUpper
)
131 bug("[KRN] Task %s went out of stack limits\n", task
->tc_Node
.ln_Name
);
132 bug("[KRN] Lower %p, upper %p, SP %p\n", task
->tc_SPLower
, task
->tc_SPUpper
, task
->tc_SPReg
);
133 Alert(AT_DeadEnd
|AN_StackProbe
);
136 if (task
->tc_Flags
& TF_LAUNCH
)
137 AROS_UFC1(void, task
->tc_Launch
, AROS_UFCA(struct ExecBase
*, SysBase
, A6
));
139 /* Leave interrupt and jump to the new task */