Don't flush caches when waiting for free MailBox slot in VC. Instead use
[AROS.git] / rom / kernel / kernel_scheduler.c
blob8a6239b7b24e163c9c4c845c4293bd665328afc5
1 /*
2 Copyright © 1995-2013, 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 D(x)
19 * Schedule the currently running task away. Put it into the TaskReady list
20 * in some smart way. This function is subject of change and it will be probably replaced
21 * by some plugin system in the future
23 BOOL core_Schedule(void)
25 struct Task *task = SysBase->ThisTask;
27 D(bug("[KRN] core_Schedule()\n"));
29 SysBase->AttnResched &= ~ARF_AttnSwitch;
31 /* If task has pending exception, reschedule it so that the dispatcher may handle the exception */
32 if (!(task->tc_Flags & TF_EXCEPT))
34 BYTE pri;
36 /* Is the TaskReady empty? If yes, then the running task is the only one. Let it work */
37 if (IsListEmpty(&SysBase->TaskReady))
38 return FALSE;
40 /* Does the TaskReady list contains tasks with priority equal or lower than current task?
41 * If so, then check further... */
42 pri = ((struct Task*)GetHead(&SysBase->TaskReady))->tc_Node.ln_Pri;
43 if (pri <= task->tc_Node.ln_Pri)
45 /* If the running task did not used it's whole quantum yet, let it work */
46 if (!(SysBase->SysFlags & SFF_QuantumOver))
47 return FALSE;
51 /*
52 * If we got here, then the rescheduling is necessary.
53 * Put the task into the TaskReady list.
55 D(bug("[KRN] Setting task 0x%p (%s) to READY\n", task, task->tc_Node.ln_Name));
56 task->tc_State = TS_READY;
57 Enqueue(&SysBase->TaskReady, &task->tc_Node);
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 = SysBase->ThisTask;
68 D(bug("[KRN] core_Switch(): Old task = %p (%s)\n", task, task->tc_Node.ln_Name));
70 #ifndef __mc68000
71 if (task->tc_SPReg <= task->tc_SPLower || task->tc_SPReg > task->tc_SPUpper)
73 bug("[KRN] Task %s went out of stack limits\n", task->tc_Node.ln_Name);
74 bug("[KRN] Lower %p, upper %p, SP %p\n", task->tc_SPLower, task->tc_SPUpper, task->tc_SPReg);
76 * Suspend the task to stop it from causing more harm. In some rare cases, if the task is holding
77 * lock on some global/library semaphore it will most likelly mean immenent freeze. In most cases
78 * however, user will be shown an alert.
80 Remove(&task->tc_Node);
81 task->tc_SigWait = 0;
82 task->tc_State = TS_WAIT;
83 Enqueue(&SysBase->TaskWait, &task->tc_Node);
85 Alert(AN_StackProbe);
87 #endif
89 task->tc_IDNestCnt = SysBase->IDNestCnt;
91 if (task->tc_Flags & TF_SWITCH)
92 AROS_UFC1NR(void, task->tc_Switch, AROS_UFCA(struct ExecBase *, SysBase, A6));
96 * Task dispatcher. Basically it may be the same one no matter
97 * what scheduling algorithm is used (except SysBase->Elapsed reloading)
99 struct Task *core_Dispatch(void)
101 struct Task *task;
103 D(bug("[KRN] core_Dispatch()\n"));
105 task = (struct Task *)REMHEAD(&SysBase->TaskReady);
106 if (!task)
108 /* Is the list of ready tasks empty? Well, go idle. */
109 D(bug("[KRN] No ready tasks, entering sleep mode\n"));
112 * Idle counter is incremented every time when we enter here,
113 * not only once. This is correct.
115 SysBase->IdleCount++;
116 SysBase->AttnResched |= ARF_AttnSwitch;
118 return NULL;
121 SysBase->DispCount++;
122 SysBase->IDNestCnt = task->tc_IDNestCnt;
123 SysBase->ThisTask = task;
124 SysBase->Elapsed = SysBase->Quantum;
125 SysBase->SysFlags &= ~SFF_QuantumOver;
126 task->tc_State = TS_RUN;
128 D(bug("[KRN] New task = %p (%s)\n", task, task->tc_Node.ln_Name));
131 * Check the stack of the task we are about to launch.
132 * Unfortunately original m68k programs can change stack manually without updating SPLower or SPUpper.
133 * For example WB3.1 C:SetPatch adds exec/OpenDevice() patch that swaps stacks manually.
134 * Result is that _all_ programs that call OpenDevice() crash if stack is checked.
136 #ifndef __mc68000
137 if (task->tc_SPReg <= task->tc_SPLower || task->tc_SPReg > task->tc_SPUpper)
139 /* Don't let the task run, switch it away (raising Alert) and dispatch another task */
140 core_Switch();
141 return core_Dispatch();
143 #endif
145 if (task->tc_Flags & TF_LAUNCH)
146 AROS_UFC1NR(void, task->tc_Launch, AROS_UFCA(struct ExecBase *, SysBase, A6));
148 /* Leave interrupt and jump to the new task */
149 return task;