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

📄 sched.c

📁 带中文注释的Linux+0.11+源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
// 指定软盘到正常运转状态所需延迟滴答数(时间)。// nr -- 软驱号(0-3),返回值为滴答数。intticks_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];}// 等待指定软驱马达启动所需时间。voidfloppy_on (unsigned int nr){  cli ();			// 关中断。  while (ticks_to_floppy_on (nr))	// 如果马达启动定时还没到,就一直把当前进程置    sleep_on (nr + wait_motor);	// 为不可中断睡眠状态并放入等待马达运行的队列中。  sti ();			// 开中断。}// 置关闭相应软驱马达停转定时器(3 秒)。voidfloppy_off (unsigned int nr){  moff_timer[nr] = 3 * HZ;}// 软盘定时处理子程序。更新马达启动定时值和马达关闭停转计时值。该子程序是在时钟定时// 中断中被调用,因此每一个滴答(10ms)被调用一次,更新马达开启或停转定时器的值。如果某// 一个马达停转定时到,则将数字输出寄存器马达启动位复位。voiddo_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()- 定时时间到时执行的函数。voidadd_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 表示内核代码在执行。// 对于一个进程由于执行时间片用完时,则进行任务切换。并执行一个计时更新工作。voiddo_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) (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。intsys_alarm (long seconds){  int old = current->alarm;  if (old)    old = (old - jiffies) / HZ;  current->alarm = (seconds > 0) ? (jiffies + HZ * seconds) : 0;  return (old);}// 取当前进程号pid。intsys_getpid (void){  return current->pid;}// 取父进程号ppid。intsys_getppid (void){  return current->father;}// 取用户号uid。intsys_getuid (void){  return current->uid;}// 取euid。intsys_geteuid (void){  return current->euid;}// 取组号gid。intsys_getgid (void){  return current->gid;}// 取egid。intsys_getegid (void){  return current->egid;}// 系统调用功能 -- 降低对CPU 的使用优先权(有人会用吗??)。// 应该限制increment 大于0,否则的话,可使优先权增大!!intsys_nice (long increment){  if (current->priority - increment > 0)    current->priority -= increment;  return 0;}// 调度程序的初始化子程序。voidsched_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 + -