void show_task(
int
nr,struct task_struct
*
p)
/
/
nr就是pid
{
int
i,j
=
4096
-
sizeof(struct task_struct);
printk(
"%d: pid=%d, state=%d, "
,nr,p
-
>pid,p
-
>state);
/
/
打印pid与state
i
=
0
;
while
(i<j && !((char
*
)(p
+
1
))[i])
i
+
+
;
printk(
"%d (of %d) chars free in kernel stack\n\r"
,i,j);
/
/
打印栈
}
void show_stat(void)
{
int
i;
for
(i
=
0
;i<NR_TASKS;i
+
+
)
if
(task[i])
show_task(i,task[i]);
}
extern void mem_use(void);
extern
int
timer_interrupt(void);
extern
int
system_call(void);
union task_union {
struct task_struct task;
char stack[PAGE_SIZE];
};
static union task_union init_task
=
{INIT_TASK,};
long
volatile jiffies
=
0
;
long
startup_time
=
0
;
struct task_struct
*
current
=
&(init_task.task);
struct task_struct
*
last_task_used_math
=
NULL;
struct task_struct
*
task[NR_TASKS]
=
{&(init_task.task), };
long
user_stack [ PAGE_SIZE>>
2
] ;
struct {
long
*
a;
short b;
} stack_start
=
{ & user_stack [PAGE_SIZE>>
2
] ,
0x10
};
/
*
*
'math_state_restore()'
saves the current math information
in
the
*
old math state array,
and
gets the new ones
from
the current task
*
/
void math_state_restore()
/
/
进程切换时完成协处理器中寄存器的切换
{
if
(last_task_used_math
=
=
current)
return
;
__asm__(
"fwait"
);
if
(last_task_used_math) {
__asm__(
"fnsave %0"
::
"m"
(last_task_used_math
-
>tss.i387));
}
last_task_used_math
=
current;
if
(current
-
>used_math) {
__asm__(
"frstor %0"
::
"m"
(current
-
>tss.i387));
}
else
{
__asm__(
"fninit"
::);
current
-
>used_math
=
1
;
}
}
/
*
*
'schedule()'
is
the scheduler function. This
is
GOOD CODE! There
*
probably won't be
any
reason to change this, as it should work well
*
in
all
circumstances (ie gives IO
-
bound processes good response etc).
*
The one thing you might take a look at
is
the signal
-
handler code here.
*
*
NOTE!! Task
0
is
the
'idle'
task, which gets called when no other
*
tasks can run. It can
not
be killed,
and
it cannot sleep. The
'state'
*
information
in
task[
0
]
is
never used.
*
/
void schedule(void)
{
int
i,
next
,c;
struct task_struct
*
*
p;
/
*
check alarm, wake up
any
interruptible tasks that have got a signal
*
/
/
*
*
/
for
(p
=
&LAST_TASK ; p > &FIRST_TASK ;
-
-
p)
/
/
从后往前遍历
if
(
*
p) {
/
/
若进程存在
if
((
*
p)
-
>alarm && (
*
p)
-
>alarm < jiffies) {
/
/
若alarm不为空且小于jiffies(此处是
0
)
(
*
p)
-
>signal |
=
(
1
<<(SIGALRM
-
1
));
(
*
p)
-
>alarm
=
0
;
}
if
(((
*
p)
-
>signal & ~(_BLOCKABLE & (
*
p)
-
>blocked)) &&
/
/
进程不理会某些信号;并且进程是可中断睡眠状态
(
*
p)
-
>state
=
=
TASK_INTERRUPTIBLE)
(
*
p)
-
>state
=
TASK_RUNNING;
}
/
*
this
is
the scheduler proper:
*
/
while
(
1
) {
/
/
进行counter的比较,来决定进程的调用
c
=
-
1
;
next
=
0
;
i
=
NR_TASKS;
p
=
&task[NR_TASKS];
while
(
-
-
i) {
if
(!
*
-
-
p)
continue
;
if
((
*
p)
-
>state
=
=
TASK_RUNNING && (
*
p)
-
>counter > c)
c
=
(
*
p)
-
>counter,
next
=
i;
/
/
遍历之后,会将counter的最大值赋给c,并且
next
存着最大counter的pid
}
if
(c)
break
;
for
(p
=
&LAST_TASK ; p > &FIRST_TASK ;
-
-
p)
if
(
*
p)
(
*
p)
-
>counter
=
((
*
p)
-
>counter >>
1
)
+
/
/
counter
=
counter
/
2
+
priority
(
*
p)
-
>priority;
}
switch_to(
next
);
/
/
进程切换
}
/
*
这部分代码的目的是在所有就绪状态的任务进程中筛选出counter值最大的进程
ID
。之后如果counter值不为
0
则进入调度这个进程执行,如果counter值为
0
,则说明所有就绪状态的进程的时间片都已用完,需要重新调整所有进程的时间片。
*
/
/
*
struct {
long
a,b;} __tmp; \
__asm__(
"cmpl %%ecx,_current\n\t"
\
"je 1f\n\t"
\
"movw %%dx,%1\n\t"
\
"xchgl %%ecx,_current\n\t"
\
"ljmp %0\n\t"
\
"cmpl %%ecx,_last_task_used_math\n\t"
\
"jne 1f\n\t"
\
"clts\n"
\
"1:"
\
::
"m"
(
*
&__tmp.a),
"m"
(
*
&__tmp.b), \
"d"
(_TSS(n)),
"c"
((
long
) task[n])); \
}
*
/
int
sys_pause(void)
{
current
-
>state
=
TASK_INTERRUPTIBLE;
schedule();
return
0
;
}
void sleep_on(struct task_struct
*
*
p)
/
/
当p进程想访问cpu的某个资源,但是该资源被占用;
{
struct task_struct
*
tmp;
if
(!p)
return
;
if
(current
=
=
&(init_task.task))
/
/
如果当前进程为
0
号进程时,就返回,不能sleep
panic(
"task[0] trying to sleep"
);
tmp
=
*
p;
*
p
=
current;
/
/
将p赋为当前进程
current
-
>state
=
TASK_UNINTERRUPTIBLE;
schedule();
if
(tmp)
tmp
-
>state
=
0
;
}
void interruptible_sleep_on(struct task_struct
*
*
p)
{
struct task_struct
*
tmp;
if
(!p)
return
;
if
(current
=
=
&(init_task.task))
panic(
"task[0] trying to sleep"
);
tmp
=
*
p;
*
p
=
current;
repeat: current
-
>state
=
TASK_INTERRUPTIBLE;
schedule();
if
(
*
p &&
*
p !
=
current) {
(
*
*
p).state
=
0
;
goto repeat;
}
*
p
=
NULL;
if
(tmp)
tmp
-
>state
=
0
;
}
void wake_up(struct task_struct
*
*
p)
{
if
(p &&
*
p) {
(
*
*
p).state
=
0
;
*
p
=
NULL;
}
}
/
*
*
OK, here are some floppy things that shouldn't be
in
the kernel
*
proper. They are here because the floppy needs a timer,
and
this
*
was the easiest way of doing it.
*
/
static struct task_struct
*
wait_motor[
4
]
=
{NULL,NULL,NULL,NULL};
static
int
mon_timer[
4
]
=
{
0
,
0
,
0
,
0
};
static
int
moff_timer[
4
]
=
{
0
,
0
,
0
,
0
};
unsigned char current_DOR
=
0x0C
;
int
ticks_to_floppy_on(unsigned
int
nr)
{
extern unsigned char selected;
unsigned char mask
=
0x10
<< nr;
if
(nr>
3
)
panic(
"floppy_on: nr>3"
);
moff_timer[nr]
=
10000
;
/
*
100
s
=
very big :
-
)
*
/
cli();
/
*
use floppy_off to turn it off
*
/
mask |
=
current_DOR;
if
(!selected) {
mask &
=
0xFC
;
mask |
=
nr;
}
if
(mask !
=
current_DOR) {
outb(mask,FD_DOR);
if
((mask ^ current_DOR) &
0xf0
)
mon_timer[nr]
=
HZ
/
2
;
else
if
(mon_timer[nr] <
2
)
mon_timer[nr]
=
2
;
current_DOR
=
mask;
}
sti();
return
mon_timer[nr];
}
void floppy_on(unsigned
int
nr)
{
cli();
while
(ticks_to_floppy_on(nr))
sleep_on(nr
+
wait_motor);
sti();
}
void floppy_off(unsigned
int
nr)
{
moff_timer[nr]
=
3
*
HZ;
}
void do_floppy_timer(void)
{
int
i;
unsigned char mask
=
0x10
;
for
(i
=
0
; i<
4
; i
+
+
,mask <<
=
1
) {
if
(!(mask & current_DOR))
continue
;
if
(mon_timer[i]) {
if
(!
-
-
mon_timer[i])
wake_up(i
+
wait_motor);
}
else
if
(!moff_timer[i]) {
current_DOR &
=
~mask;
outb(current_DOR,FD_DOR);
}
else
moff_timer[i]
-
-
;
}
}
static struct timer_list {
long
jiffies;
void (
*
fn)();
struct timer_list
*
next
;
} timer_list[TIME_REQUESTS],
*
next_timer
=
NULL;
void add_timer(
long
jiffies, void (
*
fn)(void))
{
struct timer_list
*
p;
if
(!fn)
return
;
cli();
if
(jiffies <
=
0
)
(fn)();
else
{
for
(p
=
timer_list ; p < timer_list
+
TIME_REQUESTS ; p
+
+
)
if
(!p
-
>fn)
break
;
if
(p >
=
timer_list
+
TIME_REQUESTS)
panic(
"No more time requests free"
);
p
-
>fn
=
fn;
p
-
>jiffies
=
jiffies;
p
-
>
next
=
next_timer;
next_timer
=
p;
while
(p
-
>
next
&& p
-
>
next
-
>jiffies < p
-
>jiffies) {
p
-
>jiffies
-
=
p
-
>
next
-
>jiffies;
fn
=
p
-
>fn;
p
-
>fn
=
p
-
>
next
-
>fn;
p
-
>
next
-
>fn
=
fn;
jiffies
=
p
-
>jiffies;
p
-
>jiffies
=
p
-
>
next
-
>jiffies;
p
-
>
next
-
>jiffies
=
jiffies;
p
=
p
-
>
next
;
}
}
sti();
}
void do_timer(
long
cpl)
{
extern
int
beepcount;
extern void sysbeepstop(void);
if
(beepcount)
if
(!
-
-
beepcount)
sysbeepstop();
if
(cpl)
current
-
>utime
+
+
;
else
current
-
>stime
+
+
;
if
(next_timer) {
next_timer
-
>jiffies
-
-
;
while
(next_timer && next_timer
-
>jiffies <
=
0
) {
void (
*
fn)(void);
fn
=
next_timer
-
>fn;
next_timer
-
>fn
=
NULL;
next_timer
=
next_timer
-
>
next
;
(fn)();
}
}
if
(current_DOR &
0xf0
)
do_floppy_timer();
if
((
-
-
current
-
>counter)>
0
)
return
;
current
-
>counter
=
0
;
if
(!cpl)
return
;
schedule();
}
int
sys_alarm(
long
seconds)
{
int
old
=
current
-
>alarm;
if
(old)
old
=
(old
-
jiffies)
/
HZ;
current
-
>alarm
=
(seconds>
0
)?(jiffies
+
HZ
*
seconds):
0
;
return
(old);
}
int
sys_getpid(void)
{
return
current
-
>pid;
}
int
sys_getppid(void)
{
return
current
-
>father;
}
int
sys_getuid(void)
{
return
current
-
>uid;
}
int
sys_geteuid(void)
{
return
current
-
>euid;
}
int
sys_getgid(void)
{
return
current
-
>gid;
}
int
sys_getegid(void)
{
return
current
-
>egid;
}
int
sys_nice(
long
increment)
{
if
(current
-
>priority
-
increment>
0
)
current
-
>priority
-
=
increment;
return
0
;
}
void sched_init(void)
{
int
i;
struct desc_struct
*
p;
if
(sizeof(struct sigaction) !
=
16
)
panic(
"Struct sigaction MUST be 16 bytes"
);
set_tss_desc(gdt
+
FIRST_TSS_ENTRY,&(init_task.task.tss));
set_ldt_desc(gdt
+
FIRST_LDT_ENTRY,&(init_task.task.ldt));
p
=
gdt
+
2
+
FIRST_TSS_ENTRY;
for
(i
=
1
;i<NR_TASKS;i
+
+
) {
task[i]
=
NULL;
p
-
>a
=
p
-
>b
=
0
;
p
+
+
;
p
-
>a
=
p
-
>b
=
0
;
p
+
+
;
}
/
*
Clear NT, so that we won't have troubles with that later on
*
/
__asm__(
"pushfl ; andl $0xffffbfff,(%esp) ; popfl"
);
ltr(
0
);
lldt(
0
);
outb_p(
0x36
,
0x43
);
/
*
binary, mode
3
, LSB
/
MSB, ch
0
*
/
outb_p(LATCH &
0xff
,
0x40
);
/
*
LSB
*
/
outb(LATCH >>
8
,
0x40
);
/
*
MSB
*
/
set_intr_gate(
0x20
,&timer_interrupt);
outb(inb_p(
0x21
)&~
0x01
,
0x21
);
set_system_gate(
0x80
,&system_call);
}