说明
sched.c是内核中有关进程调度管理的程序,其中包括有关调度的基本函数以及一些简单的系统调用函数
代码解析
// 任务结构定义,和一些有关描述符参数设置和获取的程序
#include <linux/sched.h>
// 内核常用函数的原型定义
#include <linux/kernel.h>
// 系统调用头文件
#include <linux/sys.h>
// 软驱头文件,含有软盘控制器参数的一些定义
#include <linux/fdreg.h>
// 定义了设置或修改描述符/中断门等宏汇编
#include <asm/system.h>
// 定义硬件端口输入输出宏汇编
#include <asm/io.h>
// 定义有关段寄存器操作的汇编函数
#include <asm/segment.h>
// 定义信号符号常量
#include <signal.h>
// 信号操作宏
#define _S(nr) (1<<((nr)-1))
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
// 内核调试函数
void show_task(int nr,struct task_struct * p)
{
int i,j = 4096-sizeof(struct task_struct);
printk("%d: pid=%d, state=%d, ",nr,p->pid,p->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]);
}
// 8253定时芯片的输入时钟频率
#define LATCH (1193180/HZ)
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;
// 1970-0-0-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 };
// 用于保存原任务协处理器状态并恢复新调来的当前任务的协处理器执行状态
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;
}
}
// 任务调度函数
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) {
(*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) {
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;
}
if (c) break;
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
if (*p)
(*p)->counter = ((*p)->counter >> 1) +
(*p)->priority;
}
switch_to(next);
}
// 系统调用,将当前任务转换为可中断的等待状态
int sys_pause(void)
{
current->state = TASK_INTERRUPTIBLE;
schedule();
return 0;
}
// 将当前任务置为不可中断的等待状态,并让睡眠队列头指针指向当前任务
void 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;
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;
}
// 唤醒*p只想的任务,*p是任务等待队列头指针
void wake_up(struct task_struct **p)
{
if (p && *p) {
(**p).state=0;
*p=NULL;
}
}
// 定义用于处理软驱的定时
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]--;
}
}
// 定时器数量
#define TIME_REQUESTS 64
// 定时器链表结构和定时器数组
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();
}
// 时钟中断C函数处理程序
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;
}
// 降低对CPU的使用优先级
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);
}