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

📄 sched.c

📁 linux0.11的vc下的源代码 注释很详细
💻 C
📖 第 1 页 / 共 2 页
字号:
	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);	// 更新数字输出寄存器。		}		else			moff_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) ()){	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++;	else		current->stime++;// 如果有用户的定时器存在,则将链表第1 个定时器的值减1。如果已等于0,则调用相应的处理// 程序,并将该处理程序指针置为空。然后去掉该项定时器。	if (next_timer)	{				// next_timer 是定时器链表的头指针(见270 行)。		next_timer->jiffies--;		while (next_timer && next_timer->jiffies <= 0)		{			void (*fn) ();	// 这里插入了一个函数指针定义!!!??			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++;	}/* 清除标志寄存器中的位NT,这样以后就不会有麻烦 */// NT 标志用于控制程序的递归调用(Nested Task)。当NT 置位时,那么当前中断任务执行// iret 指令时就会引起任务切换。NT 指出TSS 中的back_link 字段是否有效。//  __asm__ ("pushfl ; andl $0xffffbfff,(%esp) ; popfl");	// 复位NT 标志。
	_asm pushfd; _asm and dword ptr ss:[esp],0xffffbfff; _asm popfd;	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 + -