Updated PCI IDs to latest snapshot.
[tangerine.git] / arch / all-mingw32 / kernel / host_scheduler.c
blobcbc23cfa16e0a4c0f5a91afafd4540c5ff31451c
1 #define DEBUG 0
3 #include <aros/system.h>
4 #include <windows.h>
5 #define __typedef_LONG /* LONG, ULONG, WORD, BYTE and BOOL are declared in Windows headers. Looks like everything */
6 #define __typedef_WORD /* is the same except BOOL. It's defined to short on AROS and to int on Windows. This means */
7 #define __typedef_BYTE /* that you can't use it in OS-native part of the code and can't use any AROS structure */
8 #define __typedef_BOOL /* definition that contains BOOL. */
9 typedef unsigned AROS_16BIT_TYPE UWORD;
10 typedef unsigned char UBYTE;
12 #include <stddef.h>
13 #include <stdio.h>
14 #include <exec/lists.h>
15 #include <exec/execbase.h>
16 #include <hardware/intbits.h>
17 #include "etask.h"
18 #include "kernel_intern.h"
19 #include "host_debug.h"
20 #include "cpucontext.h"
22 /* We have to redefine these flags here because including exec_intern.h causes conflicts
23 between dos.h and WinAPI headers. This needs to be fixed - Pavel Fedin <sonic_amiga@rambler.ru */
24 #define SFB_SoftInt 5 /* There is a software interrupt */
25 #define SFF_SoftInt (1L<<5)
27 #define ARB_AttnSwitch 7 /* Delayed Switch() pending */
28 #define ARF_AttnSwitch (1L<<7)
29 #define ARB_AttnDispatch 15 /* Delayed Dispatch() pending */
30 #define ARF_AttnDispatch (1L<<15)
32 /* We also have to define needed exec functions here because proto/exec.h also conflicts with
33 WinAPI headers. */
34 #define Exception() AROS_LC0NR(void, Exception, struct ExecBase *, SysBase, 11, Exec)
35 #define Enqueue(arg1, arg2) AROS_LC2NR(void, Enqueue, \
36 AROS_LCA(struct List *,(arg1),A0), \
37 AROS_LCA(struct Node *,(arg2),A1), \
38 struct ExecBase *, SysBase, 45, Exec)
41 * Be careful with this, actually enabling this causes AROS to abort on first exception
42 * because of OutputDebugString() calls. Looks like WinAPI functions love to perform stack
43 * check and silently abort if they think something is wrong.
45 #define DINT(x)
46 #define DS(x)
47 #define DSLEEP(x)
49 static inline void core_LeaveInterrupt(void)
51 struct ExecBase *SysBase = *SysBasePtr;
53 DINT(bug("[KRN] core_LeaveInterrupt(): IDNestCnt is %d\n", SysBase->IDNestCnt));
54 if ((char )SysBase->IDNestCnt < 0) {
55 core_intr_enable();
60 * Task dispatcher. Basically it may be the same one no matter what scheduling algorithm is used
62 void core_Dispatch(CONTEXT *regs)
64 struct ExecBase *SysBase = *SysBasePtr;
65 struct Task *task;
66 struct AROSCPUContext *ctx;
68 Ints_Enabled = 0;
69 D(bug("[KRN] core_Dispatch()\n"));
71 /*
72 * Is the list of ready tasks empty? Well, increment the idle switch cound and stop the main thread.
74 if (IsListEmpty(&SysBase->TaskReady))
76 if (!Sleep_Mode) {
77 SysBase->IdleCount++;
78 SysBase->AttnResched |= ARF_AttnSwitch;
79 DSLEEP(bug("[KRN] TaskReady list empty. Sleeping for a while...\n"));
80 /* We are entering sleep mode */
81 Sleep_Mode = SLEEP_MODE_PENDING;
84 core_LeaveInterrupt();
85 return;
88 Sleep_Mode = SLEEP_MODE_OFF;
89 SysBase->DispCount++;
91 /* Get the first task from the TaskReady list, and populate it's settings through Sysbase */
92 task = (struct Task *)REMHEAD(&SysBase->TaskReady);
93 SysBase->ThisTask = task;
94 SysBase->Elapsed = SysBase->Quantum;
95 SysBase->SysFlags &= ~0x2000;
96 task->tc_State = TS_RUN;
97 SysBase->IDNestCnt = task->tc_IDNestCnt;
99 DS(bug("[KRN] New task = %p (%s)\n", task, task->tc_Node.ln_Name));
101 /* Handle tasks's flags */
102 if (task->tc_Flags & TF_EXCEPT)
103 Exception();
105 if (task->tc_Flags & TF_LAUNCH)
107 task->tc_Launch(SysBase);
110 /* Restore the task's state */
111 ctx = (struct AROSCPUContext *)GetIntETask(task)->iet_Context;
112 CopyMemory(regs, ctx, sizeof(CONTEXT));
113 *LastErrorPtr = ctx->LastError;
115 /* Leave interrupt and jump to the new task */
116 core_LeaveInterrupt();
119 void core_Switch(CONTEXT *regs)
121 struct ExecBase *SysBase = *SysBasePtr;
122 struct Task *task;
123 struct AROSCPUContext *ctx;
125 Ints_Enabled = 0;
126 D(bug("[KRN] core_Switch()\n"));
128 task = SysBase->ThisTask;
130 DS(bug("[KRN] Old task = %p (%s)\n", task, task->tc_Node.ln_Name));
132 /* Copy current task's context into the ETask structure */
133 ctx = (struct AROSCPUContext *)GetIntETask(task)->iet_Context;
134 CopyMemory(ctx, regs, sizeof(CONTEXT));
135 ctx->LastError = *LastErrorPtr;
137 /* store IDNestCnt into tasks's structure */
138 task->tc_IDNestCnt = SysBase->IDNestCnt;
139 task->tc_SPReg = (APTR)regs->Esp;
141 /* And enable interrupts */
142 SysBase->IDNestCnt = -1;
144 /* TF_SWITCH flag set? Call the switch routine */
145 if (task->tc_Flags & TF_SWITCH)
147 task->tc_Switch(SysBase);
150 core_Dispatch(regs);
155 * Schedule the currently running task away. Put it into the TaskReady list
156 * in some smart way. This function is subject of change and it will be probably replaced
157 * by some plugin system in the future
159 void core_Schedule(CONTEXT *regs)
161 struct ExecBase *SysBase = *SysBasePtr;
162 struct Task *task;
164 Ints_Enabled = 0;
165 D(bug("[KRN] core_Schedule()\n"));
167 task = SysBase->ThisTask;
169 /* Clear the pending switch flag. */
170 SysBase->AttnResched &= ~ARF_AttnSwitch;
172 /* If task has pending exception, reschedule it so that the dispatcher may handle the exception */
173 if (!(task->tc_Flags & TF_EXCEPT))
175 /* Is the TaskReady empty? If yes, then the running task is the only one. Let it work */
176 if (IsListEmpty(&SysBase->TaskReady)) {
177 core_LeaveInterrupt();
178 return;
181 /* Does the TaskReady list contains tasks with priority equal or lower than current task?
182 * If so, then check further... */
183 if (((struct Task*)GetHead(&SysBase->TaskReady))->tc_Node.ln_Pri <= task->tc_Node.ln_Pri)
185 /* If the running task did not used it's whole quantum yet, let it work */
186 if (!(SysBase->SysFlags & 0x2000))
188 core_LeaveInterrupt();
189 return;
195 * If we got here, then the rescheduling is necessary.
196 * Put the task into the TaskReady list.
198 task->tc_State = TS_READY;
199 Enqueue(&SysBase->TaskReady, (struct Node *)task);
201 /* Select new task to run */
202 core_Switch(regs);
207 * Leave the interrupt. This function receives the register frame used to leave the supervisor
208 * mode. It reschedules the task if it was asked for.
210 void core_ExitInterrupt(CONTEXT *regs)
212 struct ExecBase *SysBase = *SysBasePtr;
213 char TDNestCnt;
215 D(bug("[Scheduler] core_ExitInterrupt\n"));
216 if (SysBase)
218 /* Soft interrupt requested? It's high time to do it */
219 if (SysBase->SysFlags & SFF_SoftInt) {
220 DS(bug("[Scheduler] Causing SoftInt\n"));
221 core_Cause(SysBase);
224 if (Sleep_Mode) {
225 core_Dispatch(regs);
226 return;
229 /* If task switching is disabled, leave immediatelly */
230 TDNestCnt = SysBase->TDNestCnt; /* BYTE is unsigned in Windows so we can't use SysBase->TDNestCnt directly */
231 DS(bug("[Scheduler] TDNestCnt is %d\n", TDNestCnt));
232 if (TDNestCnt < 0)
235 * Do not disturb task if it's not necessary.
236 * Reschedule only if switch pending flag is set. Exit otherwise.
238 if (SysBase->AttnResched & ARF_AttnSwitch)
240 DS(bug("[Scheduler] Rescheduling\n"));
241 core_Schedule(regs);
245 DS(else printf("[Scheduler] SysBase is NULL\n");)
248 void core_Cause(struct ExecBase *SysBase)
250 struct IntVector *iv = &SysBase->IntVects[INTB_SOFTINT];
252 /* If the SoftInt vector in SysBase is set, call it. It will do the rest for us */
253 if (iv->iv_Code)
255 iv->iv_Code(0, 0, 0, iv->iv_Code, SysBase);