3 #include <aros/system.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
;
14 #include <exec/lists.h>
15 #include <exec/execbase.h>
16 #include <hardware/intbits.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
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.
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) {
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
;
66 struct AROSCPUContext
*ctx
;
69 D(bug("[KRN] core_Dispatch()\n"));
72 * Is the list of ready tasks empty? Well, increment the idle switch cound and stop the main thread.
74 if (IsListEmpty(&SysBase
->TaskReady
))
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();
88 Sleep_Mode
= SLEEP_MODE_OFF
;
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
)
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
;
123 struct AROSCPUContext
*ctx
;
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
);
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
;
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();
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();
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 */
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
;
215 D(bug("[Scheduler] core_ExitInterrupt\n"));
218 /* Soft interrupt requested? It's high time to do it */
219 if (SysBase
->SysFlags
& SFF_SoftInt
) {
220 DS(bug("[Scheduler] Causing SoftInt\n"));
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
));
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"));
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 */
255 iv
->iv_Code(0, 0, 0, iv
->iv_Code
, SysBase
);