rom/exec: implementation of task specific storage.
[AROS.git] / rom / kernel / kernel_scheduler.c
blobdb89606da9d7c60b5dd0fa73d9cb9779057b18f7
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"
12 //#define D(x)
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))
30 BYTE pri;
32 /* Is the TaskReady empty? If yes, then the running task is the only one. Let it work */
33 if (IsListEmpty(&SysBase->TaskReady))
34 return FALSE;
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))
43 return FALSE;
47 /*
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 */
56 return TRUE;
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)
78 struct Task *task;
80 D(bug("[KRN] core_Dispatch()\n"));
82 task = (struct Task *)REMHEAD(&SysBase->TaskReady);
83 if (!task)
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. */
90 SysBase->IdleCount++;
91 SysBase->AttnResched |= ARF_AttnSwitch;
93 return NULL;
96 SysBase->DispCount++;
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.
128 #ifndef __mc68000
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);
135 #endif
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 */
140 return task;