summaryrefslogtreecommitdiffstats
path: root/src/kernel/sched.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/sched.c')
-rw-r--r--src/kernel/sched.c412
1 files changed, 412 insertions, 0 deletions
diff --git a/src/kernel/sched.c b/src/kernel/sched.c
new file mode 100644
index 0000000..15d839b
--- /dev/null
+++ b/src/kernel/sched.c
@@ -0,0 +1,412 @@
1/*
2 * linux/kernel/sched.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7/*
8 * 'sched.c' is the main kernel file. It contains scheduling primitives
9 * (sleep_on, wakeup, schedule etc) as well as a number of simple system
10 * call functions (type getpid(), which just extracts a field from
11 * current-task
12 */
13#include <linux/sched.h>
14#include <linux/kernel.h>
15#include <linux/sys.h>
16#include <linux/fdreg.h>
17#include <asm/system.h>
18#include <asm/io.h>
19#include <asm/segment.h>
20
21#include <signal.h>
22
23#define _S(nr) (1<<((nr)-1))
24#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
25
26void show_task(int nr,struct task_struct * p)
27{
28 int i,j = 4096-sizeof(struct task_struct);
29
30 printk("%d: pid=%d, state=%d, ",nr,p->pid,p->state);
31 i=0;
32 while (i<j && !((char *)(p+1))[i])
33 i++;
34 printk("%d (of %d) chars free in kernel stack\n\r",i,j);
35}
36
37void show_stat(void)
38{
39 int i;
40
41 for (i=0;i<NR_TASKS;i++)
42 if (task[i])
43 show_task(i,task[i]);
44}
45
46#define LATCH (1193180/HZ)
47
48extern void mem_use(void);
49
50extern int timer_interrupt(void);
51extern int system_call(void);
52
53union task_union {
54 struct task_struct task;
55 char stack[PAGE_SIZE];
56};
57
58static union task_union init_task = {INIT_TASK,};
59
60long volatile jiffies=0;
61long startup_time=0;
62struct task_struct *current = &(init_task.task);
63struct task_struct *last_task_used_math = NULL;
64
65struct task_struct * task[NR_TASKS] = {&(init_task.task), };
66
67long user_stack [ PAGE_SIZE>>2 ] ;
68
69struct {
70 long * a;
71 short b;
72 } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 };
73/*
74 * 'math_state_restore()' saves the current math information in the
75 * old math state array, and gets the new ones from the current task
76 */
77void math_state_restore()
78{
79 if (last_task_used_math == current)
80 return;
81 __asm__("fwait");
82 if (last_task_used_math) {
83 __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));
84 }
85 last_task_used_math=current;
86 if (current->used_math) {
87 __asm__("frstor %0"::"m" (current->tss.i387));
88 } else {
89 __asm__("fninit"::);
90 current->used_math=1;
91 }
92}
93
94/*
95 * 'schedule()' is the scheduler function. This is GOOD CODE! There
96 * probably won't be any reason to change this, as it should work well
97 * in all circumstances (ie gives IO-bound processes good response etc).
98 * The one thing you might take a look at is the signal-handler code here.
99 *
100 * NOTE!! Task 0 is the 'idle' task, which gets called when no other
101 * tasks can run. It can not be killed, and it cannot sleep. The 'state'
102 * information in task[0] is never used.
103 */
104void schedule(void)
105{
106 int i,next,c;
107 struct task_struct ** p;
108
109/* check alarm, wake up any interruptible tasks that have got a signal */
110
111 for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
112 if (*p) {
113 if ((*p)->alarm && (*p)->alarm < jiffies) {
114 (*p)->signal |= (1<<(SIGALRM-1));
115 (*p)->alarm = 0;
116 }
117 if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
118 (*p)->state==TASK_INTERRUPTIBLE)
119 (*p)->state=TASK_RUNNING;
120 }
121
122/* this is the scheduler proper: */
123
124 while (1) {
125 c = -1;
126 next = 0;
127 i = NR_TASKS;
128 p = &task[NR_TASKS];
129 while (--i) {
130 if (!*--p)
131 continue;
132 if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
133 c = (*p)->counter, next = i;
134 }
135 if (c) break;
136 for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
137 if (*p)
138 (*p)->counter = ((*p)->counter >> 1) +
139 (*p)->priority;
140 }
141 switch_to(next);
142}
143
144int sys_pause(void)
145{
146 current->state = TASK_INTERRUPTIBLE;
147 schedule();
148 return 0;
149}
150
151void sleep_on(struct task_struct **p)
152{
153 struct task_struct *tmp;
154
155 if (!p)
156 return;
157 if (current == &(init_task.task))
158 panic("task[0] trying to sleep");
159 tmp = *p;
160 *p = current;
161 current->state = TASK_UNINTERRUPTIBLE;
162 schedule();
163 if (tmp)
164 tmp->state=0;
165}
166
167void interruptible_sleep_on(struct task_struct **p)
168{
169 struct task_struct *tmp;
170
171 if (!p)
172 return;
173 if (current == &(init_task.task))
174 panic("task[0] trying to sleep");
175 tmp=*p;
176 *p=current;
177repeat: current->state = TASK_INTERRUPTIBLE;
178 schedule();
179 if (*p && *p != current) {
180 (**p).state=0;
181 goto repeat;
182 }
183 *p=NULL;
184 if (tmp)
185 tmp->state=0;
186}
187
188void wake_up(struct task_struct **p)
189{
190 if (p && *p) {
191 (**p).state=0;
192 *p=NULL;
193 }
194}
195
196/*
197 * OK, here are some floppy things that shouldn't be in the kernel
198 * proper. They are here because the floppy needs a timer, and this
199 * was the easiest way of doing it.
200 */
201static struct task_struct * wait_motor[4] = {NULL,NULL,NULL,NULL};
202static int mon_timer[4]={0,0,0,0};
203static int moff_timer[4]={0,0,0,0};
204unsigned char current_DOR = 0x0C;
205
206int ticks_to_floppy_on(unsigned int nr)
207{
208 extern unsigned char selected;
209 unsigned char mask = 0x10 << nr;
210
211 if (nr>3)
212 panic("floppy_on: nr>3");
213 moff_timer[nr]=10000; /* 100 s = very big :-) */
214 cli(); /* use floppy_off to turn it off */
215 mask |= current_DOR;
216 if (!selected) {
217 mask &= 0xFC;
218 mask |= nr;
219 }
220 if (mask != current_DOR) {
221 outb(mask,FD_DOR);
222 if ((mask ^ current_DOR) & 0xf0)
223 mon_timer[nr] = HZ/2;
224 else if (mon_timer[nr] < 2)
225 mon_timer[nr] = 2;
226 current_DOR = mask;
227 }
228 sti();
229 return mon_timer[nr];
230}
231
232void floppy_on(unsigned int nr)
233{
234 cli();
235 while (ticks_to_floppy_on(nr))
236 sleep_on(nr+wait_motor);
237 sti();
238}
239
240void floppy_off(unsigned int nr)
241{
242 moff_timer[nr]=3*HZ;
243}
244
245void do_floppy_timer(void)
246{
247 int i;
248 unsigned char mask = 0x10;
249
250 for (i=0 ; i<4 ; i++,mask <<= 1) {
251 if (!(mask & current_DOR))
252 continue;
253 if (mon_timer[i]) {
254 if (!--mon_timer[i])
255 wake_up(i+wait_motor);
256 } else if (!moff_timer[i]) {
257 current_DOR &= ~mask;
258 outb(current_DOR,FD_DOR);
259 } else
260 moff_timer[i]--;
261 }
262}
263
264#define TIME_REQUESTS 64
265
266static struct timer_list {
267 long jiffies;
268 void (*fn)();
269 struct timer_list * next;
270} timer_list[TIME_REQUESTS], * next_timer = NULL;
271
272void add_timer(long jiffies, void (*fn)(void))
273{
274 struct timer_list * p;
275
276 if (!fn)
277 return;
278 cli();
279 if (jiffies <= 0)
280 (fn)();
281 else {
282 for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++)
283 if (!p->fn)
284 break;
285 if (p >= timer_list + TIME_REQUESTS)
286 panic("No more time requests free");
287 p->fn = fn;
288 p->jiffies = jiffies;
289 p->next = next_timer;
290 next_timer = p;
291 while (p->next && p->next->jiffies < p->jiffies) {
292 p->jiffies -= p->next->jiffies;
293 fn = p->fn;
294 p->fn = p->next->fn;
295 p->next->fn = fn;
296 jiffies = p->jiffies;
297 p->jiffies = p->next->jiffies;
298 p->next->jiffies = jiffies;
299 p = p->next;
300 }
301 }
302 sti();
303}
304
305void do_timer(long cpl)
306{
307 extern int beepcount;
308 extern void sysbeepstop(void);
309
310 if (beepcount)
311 if (!--beepcount)
312 sysbeepstop();
313
314 if (cpl)
315 current->utime++;
316 else
317 current->stime++;
318
319 if (next_timer) {
320 next_timer->jiffies--;
321 while (next_timer && next_timer->jiffies <= 0) {
322 void (*fn)(void);
323
324 fn = next_timer->fn;
325 next_timer->fn = NULL;
326 next_timer = next_timer->next;
327 (fn)();
328 }
329 }
330 if (current_DOR & 0xf0)
331 do_floppy_timer();
332 if ((--current->counter)>0) return;
333 current->counter=0;
334 if (!cpl) return;
335 schedule();
336}
337
338int sys_alarm(long seconds)
339{
340 int old = current->alarm;
341
342 if (old)
343 old = (old - jiffies) / HZ;
344 current->alarm = (seconds>0)?(jiffies+HZ*seconds):0;
345 return (old);
346}
347
348int sys_getpid(void)
349{
350 return current->pid;
351}
352
353int sys_getppid(void)
354{
355 return current->father;
356}
357
358int sys_getuid(void)
359{
360 return current->uid;
361}
362
363int sys_geteuid(void)
364{
365 return current->euid;
366}
367
368int sys_getgid(void)
369{
370 return current->gid;
371}
372
373int sys_getegid(void)
374{
375 return current->egid;
376}
377
378int sys_nice(long increment)
379{
380 if (current->priority-increment>0)
381 current->priority -= increment;
382 return 0;
383}
384
385void sched_init(void)
386{
387 int i;
388 struct desc_struct * p;
389
390 if (sizeof(struct sigaction) != 16)
391 panic("Struct sigaction MUST be 16 bytes");
392 set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));
393 set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
394 p = gdt+2+FIRST_TSS_ENTRY;
395 for(i=1;i<NR_TASKS;i++) {
396 task[i] = NULL;
397 p->a=p->b=0;
398 p++;
399 p->a=p->b=0;
400 p++;
401 }
402/* Clear NT, so that we won't have troubles with that later on */
403 __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
404 ltr(0);
405 lldt(0);
406 outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */
407 outb_p(LATCH & 0xff , 0x40); /* LSB */
408 outb(LATCH >> 8 , 0x40); /* MSB */
409 set_intr_gate(0x20,&timer_interrupt);
410 outb(inb_p(0x21)&~0x01,0x21);
411 set_system_gate(0x80,&system_call);
412}