⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sched.c

📁 linux 0.11 内核源码。kernel-011-src.tar
💻 C
📖 第 1 页 / 共 2 页
字号:
static int moff_timer[4]={0,0,0,0};unsigned char current_DOR = 0x0C; // 数字输出寄存器(初值:允许DMA 和请求中断、启动FDC)。// 指定软盘到正常运转状态所需延迟滴答数(时间)。// nr -- 软驱号(0-3),返回值为滴答数。int ticks_to_floppy_on(unsigned int nr){extern unsigned char selected; // 当前选中的软盘号(kernel/blk_drv/floppy.c,122)。unsigned char mask = 0x10 << nr; // 所选软驱对应数字输出寄存器中启动马达比特位。if (nr>3)panic( "floppy_on: nr>3"); // 最多4 个软驱。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;}// 如果数字输出寄存器的当前值与要求的值不同,则向FDC 数字输出端口输出新值(mask)。并且如果// 要求启动的马达还没有启动,则置相应软驱的马达启动定时器值(HZ/2 = 0.5 秒或50 个滴答)。// 此后更新当前数字输出寄存器值current_DOR。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(); // 开中断。}// 置关闭相应软驱马达停转定时器(3 秒)。void floppy_off(unsigned int nr){moff_timer[nr]=3*HZ;}// 软盘定时处理子程序。更新马达启动定时值和马达关闭停转计时值。该子程序是在时钟定时// 中断中被调用,因此每一个滴答(10ms)被调用一次,更新马达开启或停转定时器的值。如果某// 一个马达停转定时到,则将数字输出寄存器马达启动位复位。void do_floppy_timer(void){int i;unsigned char mask = 0x10;for (i=0 ; i<4 ; i++,mask <<= 1) {if (!(mask & current_DOR)) // 如果不是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); // 更新数字输出寄存器。} elsemoff_timer[i]--; // 马达停转计时递减。}}#define TIME_REQUESTS 64 // 最多可有64 个定时器链表(64 个任务)。// 定时器链表结构和定时器数组。static struct timer_list {long jiffies; // 定时滴答数。void (*fn)(); // 定时处理程序。struct timer_list * next; // 下一个定时器。} timer_list[TIME_REQUESTS], * next_timer = NULL;// 添加定时器。输入参数为指定的定时值(滴答数)和相应的处理程序指针。// jiffies – 以10 毫秒计的滴答数;*fn()- 定时时间到时执行的函数。void add_timer(long jiffies, void (*fn)(void)){struct timer_list * p;// 如果定时处理程序指针为空,则退出。if (!fn)return;cli();// 如果定时值<=0,则立刻调用其处理程序。并且该定时器不加入链表中。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;// 链表项按定时值从小到大排序。在排序时减去排在前面需要的滴答数,这样在处理定时器时只要// 查看链表头的第一项的定时是否到期即可。[[?? 这段程序好象没有考虑周全。如果新插入的定时// 器值 < 原来头一个定时器值时,也应该将所有后面的定时值均减去新的第1 个的定时值。]]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 函数处理程序,在kernel/system_call.s 中的_timer_interrupt(176 行)被调用。// 参数cpl 是当前特权级0 或3,0 表示内核代码在执行。// 对于一个进程由于执行时间片用完时,则进行任务切换。并执行一个计时更新工作。void do_timer(long cpl){extern int beepcount; // 扬声器发声时间滴答数(kernel/chr_drv/console.c,697)extern void sysbeepstop(void); // 关闭扬声器(kernel/chr_drv/console.c,691)// 如果发声计数次数到,则关闭发声。(向0x61 口发送命令,复位位0 和1。位0 控制8253// 计数器2 的工作,位1 控制扬声器)。if (beepcount)if (!--beepcount)sysbeepstop();// 如果当前特权级(cpl)为0(最高,表示是内核程序在工作),则将超级用户运行时间stime 递增;// 如果cpl > 0,则表示是一般用户程序在工作,增加utime。if (cpl)current->utime++;elsecurrent->stime++;// 如果有用户的定时器存在,则将链表第1 个定时器的值减1。如果已等于0,则调用相应的处理// 程序,并将该处理程序指针置为空。然后去掉该项定时器。if (next_timer) { // next_timer 是定时器链表的头指针(见270 行)。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)(); // 调用处理函数。}}// 如果当前软盘控制器FDC 的数字输出寄存器中马达启动位有置位的,则执行软盘定时程序(245 行)。if (current_DOR & 0xf0)do_floppy_timer();if ((--current->counter)>0) return; // 如果进程运行时间还没完,则退出。current->counter=0;if (!cpl) return; // 对于超级用户程序,不依赖counter 值进行调度。schedule();}// 系统调用功能 - 设置报警定时时间值(秒)。// 如果已经设置过alarm 值,则返回旧值,否则返回0。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);}// 取当前进程号pid。int sys_getpid(void){return current->pid;}// 取父进程号ppid。int sys_getppid(void){return current->father;}// 取用户号uid。int sys_getuid(void){return current->uid;}// 取euid。int sys_geteuid(void){return current->euid;}// 取组号gid。int sys_getgid(void){return current->gid;}// 取egid。int sys_getegid(void){return current->egid;}// 系统调用功能 -- 降低对CPU 的使用优先权(有人会用吗??)。// 应该限制increment 大于0,否则的话,可使优先权增大!!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) // sigaction 是存放有关信号状态的结构。panic( "Struct sigaction MUST be 16 bytes");// 设置初始任务(任务0)的任务状态段描述符和局部数据表描述符(include/asm/system.h,65)。set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));// 清任务数组和描述符表项(注意i=1 开始,所以初始任务的描述符还在)。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 *//* 清除标志寄存器中的位NT,这样以后就不会有麻烦 */// NT 标志用于控制程序的递归调用(Nested Task)。当NT 置位时,那么当前中断任务执行// iret 指令时就会引起任务切换。NT 指出TSS 中的back_link 字段是否有效。__asm__( "pushfl ; andl $0xffffbfff,(%esp) ; popfl"); // 复位NT 标志。ltr(0); // 将任务0 的TSS 加载到任务寄存器tr。lldt(0); // 将局部描述符表加载到局部描述符表寄存器。// 注意!!是将GDT 中相应LDT 描述符的选择符加载到ldtr。只明确加载这一次,以后新任务// LDT 的加载,是CPU 根据TSS 中的LDT 项自动加载。// 下面代码用于初始化8253 定时器。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);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -