root/Whitix/trunk/kernel/sched.c

Revision 1802, 5.8 KB (checked in by mwhitworth, 3 years ago)

Remove KernelPanic test in loop.

Line 
1/*  This file is part of Whitix.
2 *
3 *  Whitix is free software; you can redistribute it and/or modify
4 *  it under the terms of the GNU General Public License as published by
5 *  the Free Software Foundation; either version 2 of the License, or
6 *  (at your option) any later version.
7 *
8 *  Whitix is distributed in the hope that it will be useful,
9 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 *  GNU General Public License for more details.
12 *
13 *  You should have received a copy of the GNU General Public License
14 *  along with Whitix; if not, write to the Free Software
15 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
16 *
17 */
18
19#include <sched.h>
20#include <error.h>
21#include <i386/process.h>
22#include <slab.h>
23#include <typedefs.h>
24#include <wait.h>
25#include <malloc.h>
26#include <fs/vfs.h>
27#include <task.h>
28#include <panic.h>
29#include <vmm.h>
30#include <module.h>
31#include <sys.h>
32
33extern struct ListHead threadList;
34
35volatile int thrNeedSchedule=false;
36struct Thread* prevThread,*currThread;
37
38SYMBOL_EXPORT(currThread);
39
40struct Process* current,*prev;
41int nrRunning; /* nrRunning is the number of threads running */
42
43SYMBOL_EXPORT(current);
44
45/***********************************************************************
46 *
47 * FUNCTION: ThrIdleFunc
48 *
49 * DESCRIPTION: The CPU idles on this function if there is nothing else
50 *                              to schedule.
51 *
52 * PARAMETERS: None.
53 *
54 * RETURNS: Nothing.
55 *
56 ***********************************************************************/
57
58void ThrIdleFunc()
59{
60        /* Setting to lowest priority means that any thread woken up will preempt this one */
61        ThrSetPriority(currThread,PRIORITY_NONE);
62
63        /* TODO: Zero out pages while there's nothing to do? */
64        while (1)
65        {
66                sti();
67                hlt();
68        }
69}
70
71/***********************************************************************
72 *
73 * FUNCTION:    ThrChooseNewThread
74 *
75 * DESCRIPTION: Go through all running threads and calculate the best
76 *                              thread to run. This is the core of the scheduling
77 *                              algorithm. This will choose the idle thread (idleTask)
78 *                              if there are no threads running.
79 *
80 * PARAMETERS:  None.
81 *
82 * RETURNS:             The next thread to run.
83 *
84 ***********************************************************************/
85
86struct Thread* ThrChooseNewThread()
87{
88        int c = -1;
89        struct Thread* thread=idleTask,*curr;
90
91        ListForEachEntry(curr,&threadList,list)
92        {
93                if (curr->quantums > c && curr->state == THR_RUNNING)
94                {
95                        c=curr->quantums;
96                        thread=curr;
97                }
98        }
99               
100        /* Recalculate quantums - all threads have no time left to run */
101        if (!c)
102        {
103                ListForEachEntry(curr,&threadList,list)
104                        curr->quantums=curr->priority + (curr->quantums >> 2);
105        }
106
107        return thread;
108}
109
110/***********************************************************************
111 *
112 * FUNCTION:    ThrSchedule
113 *
114 * DESCRIPTION: Schedules another thread to run if required.
115 *
116 * PARAMETERS:  None.
117 *
118 * RETURNS:             Nothing.
119 *
120 ***********************************************************************/
121
122void ThrSchedule()
123{
124        DWORD flags;
125        IrqSaveFlags(flags);
126
127        thrNeedSchedule=false;
128
129        /* See what's happening to the current thread - does it want to be freed? */
130        if (currThread && currThread->state == THR_DYING)
131                ThrFreeThread(currThread);
132
133        /* Cannot depend on currThread actually being valid, as it may have been freed
134         * in ThrFreeThread. */ 
135
136        prevThread=currThread;
137        prev=current;
138
139        currThread=ThrChooseNewThread();
140        current=currThread->parent;
141
142        /* The only threads without a parent process are kernel threads - who
143         * don't need their own address space as they only manipulate kernel
144         * memory, which is present in every address space.
145         */
146
147        if (current)
148        {
149                if (UNLIKELY(!prevThread))
150                        /* If there is no previous thread it has probably been freed in
151                         * _ThrFreeThread - and so the virtual address space must be
152                         * switched as soon as possible.
153                         */
154                        VirtSetCurrent(current->memManager);
155                else if (current != prev)
156                        /*
157                         * If the current and previous threads have the same address space,
158                         * there's no point switching, since the only thing it'll do is
159                         * flush the TLBs.
160                         */
161                        VirtSetCurrent(current->memManager);
162        }else if (UNLIKELY(!prevThread))
163                VirtSetCurrent(&kernelMem);
164
165        /* If we're actually switching, call the architecture-specific code to switch
166         * contexts.
167         */
168        if (prevThread != currThread)
169                ThrArchSwitch(prevThread, currThread);
170
171        IrqRestoreFlags(flags);
172}
173
174SYMBOL_EXPORT(ThrSchedule);
175
176/***********************************************************************
177 *
178 * FUNCTION:    SysYield
179 *
180 * DESCRIPTION: Give up the current thread's timeslice and schedule
181 *                              immediately.
182 *
183 * PARAMETERS:  None.
184 *
185 ***********************************************************************/
186
187int SysYield()
188{
189        currThread->quantums=0;
190        thrNeedSchedule=true;
191        return 0;
192}
193
194/* TODO: Send a kill signal once signals are implemented. */
195void ThrEndWait(struct Thread* thread)
196{
197        if (thread->parent && thread->parent->state == THR_DYING)
198        {
199                /* Kill time until process exits. */
200                while (1)
201                        SysYield();
202        }
203}
204
205SYMBOL_EXPORT(ThrEndWait);
206
207/***********************************************************************
208 *
209 * FUNCTION:    ThrInit
210 *
211 * DESCRIPTION: Sets up the architecture specifics, caches and creates
212 *                              the idle thread.
213 *
214 * PARAMETERS:  None.
215 *
216 * RETURNS:             Usual error codes.
217 *
218 ***********************************************************************/
219
220int ThrEarlyInit()
221{
222        /* Set up arch-specific data structures for multitasking here */
223        ThrArchInit();
224
225        currThread=idleTask;
226        currThread->state=THR_RUNNING;
227        currThread->refs=1;
228
229        nrRunning=0; /* The idle task isn't treated as a normal thread. */
230
231        return 0;
232}
233
234struct SysCall schedSysCall=SysEntry(SysYield, 0);
235
236extern int ThreadInit();
237extern int ProcessInit();
238
239int ThrInit()
240{
241        ThreadInit();
242        ProcessInit();
243
244        /* Register the scheduler system calls. */
245        SysRegisterCall(SYS_SCHED_BASE, &schedSysCall);
246
247        return 0;
248}
Note: See TracBrowser for help on using the browser.