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

📄 (ldd) ch06-时间流(转载).txt

📁 献给ARM初学者
💻 TXT
📖 第 1 页 / 共 4 页
字号:

       
             另一个与任务队列有关的概念是中断时间。在Linux中,中断时间是个软件上的
      概念,取决于内核的全局变量intr_count。任一时候该变量都记录了正在执行的中断处
      理程序被嵌套的层数*。
       
       
       
             一般的计算流程中,当处理器允许某个进程时,intr_count值为0。当intr_coun
      t不为零时,,执行的代码就与系统的其他部分是异步的了。这些异步代码可以是硬件中
      断的处理或者是“软件中断”-与任何进程都无关的一个任务,我们称它在“中断时间
      内”运行。这种异步代码是不允许做某些操作的;特别的,它不能使当前进程进入睡眠
      ,因为current指针的值与正在运行的软件中断代码无关。
       
       
       
             典型的例子是退出系统调用时要执行的代码。如果因为某个原因此时还有任务需
      要得到执行,内核可以一退出系统调用就处理它。这是个“软件中断”,intr_count值
      在处理这个待执行的任务之前会先加1。由于主线指令流被中断了,该函数算是在“中断
      时间”内被处理的。
       
       
       
             当intr_count非零时,不能激活调度器。这也就意味着不允许调用kmalloc(GFP_

             当intr_count非零时,不能激活调度器。这也就意味着不允许调用kmalloc(GFP_
      KERNEL)。在中断时间内,只能进行原子性的分配(见第7章“掌握内存”的“优先权参数
      ”一节),而原子性的分配较“普通的”分配更容易失败。
       
             如果运行在中断时间的代码调用了调度器,类似“Aiee: scheduling in
      interrupt”这样的错误信息和以16进制显示的调用点处的地址会打印到控制台上。2.1.
      37之后的版本,oops消息也会打印出来,通过分析寄存器的值可以进行调试。在中断时
      间内如果试图非原子性地按优先权分配内存,也会显示包括着调用者的调用点处地址的
      错误信息。
       
      预定义的任务队列
      延迟任务执行的简单方法是使用内核维护的任务队列。这种队列有下面描述的四种,但
      驱动程序只能用前三种。任务队列的定义在头文件<linux/queue.h>中,你的驱动程序代
      码要将它包含(include)进来。
       
       
       
      tq_scheduler队列
       
      当调度器被运行时该队列就会被处理。因为此时调度器在被调度出的进程的上下文中运
      行,所以该队列中的任务几乎可以做任何事;它们不会在中断时运行。
       
       

       
       
      tq_timer队列
       
      该队列由定时器队列处理程序(timer tick)运行。因为该处理程序(见函数do_timer)是
      在中断时间运行的,该队列中的所有任务就也是在中断时间内运行的了。
       
       
       
      tq_immediate队列
       
      立即队列在系统调用返回时或调度器运行时尽快得到处理的(不管两种情况谁先发生了)
      。该队列是在中断时间内得到处理的。
       
       
       
      tq_disk队列
       
      1.2版的内核不再提供这种任务队列了,内存管理例程内部使用,模块不能使用。
       
       
       
      使用任务队列的一个设备驱动程序的执行流程可见图6-1。该图演示了设备驱动程序是如

      使用任务队列的一个设备驱动程序的执行流程可见图6-1。该图演示了设备驱动程序是如
      何在中断处理程序中将一个函数插入tq_scheduler队列中的。
       
       
       
      被执行的代码
       
      中断
       
      从中断返回
       
      数据
       
      关键字
       
      处理器代码
       
      调度器
       
      驱动程序代码
       
      (指向任务)
       

       
      "sync"位
       
      (指向next)
       
      图 6-1:任务队列使用的执行流程
       
      示例程序是如何工作的
             延迟计算的示例程序是jiq(Just In Queue)模块,本节中抽取了它的部分源码。
      该模块创建/proc文件,可以用dd或者其他工具来读;这与jit模块很相似。该示例程序
      使用了动态/proc文件因此不能在Linux1.2上运行。
       
       
       
             读jiq文件的进程进入睡眠状态直到缓冲区满*。缓冲区由不断运行的任务队列来
      填充。任务队列的每遍运行都将在要填充的缓冲区中添加一个字符串;该字符串记录了
      当前时间(jiffies值),该遍的current进程和intr_count值。
       
       
       
             该/proc文件最好是用dd count=1命令一次性地读进来;如果你用cat命令,read
      方法要被多次调用,输出结果会有重迭,详情可见第4章“调试技术”的“使用/proc文
      件系统”一节。

      件系统”一节。
       
       
       
             填充缓冲区的代码都在jiq_print函数中,任务队列的每遍运行都要调用它。打
      印函数没什么意思,不在这里列出;我们还是来看看插入队列的任务的初始化代码:
       
       
       
      struct tq_struct jiq_task; /* 全局变量;初始化为零 */
       
       
       
          /* 该行在init_module()中 */
       
          jiq_task.routine = jiq_print;
       
      jiq_task.data = (void *)&jiq_data;
       
       
       
      这里没必要清零jiq_task结构变量的sync域和next域,因为静态变量已由编译器初始化
      为零了。

      为零了。
       
      调度器队列
      最容易使用的任务队列是tq_scheduler队列,因为该队列中的任务不会在中断时间内运
      行,因此少了很多限制。
       
       
       
      /proc/jiqsched文件是使用tq_scheduler队列的示例文件。该文件的read函数以如下的
      方式将任务jiq_task放进tq_scheduler队列中:
       
       
       
      /*
       
       * 使用调度器队列的例子  -- /proc/jiqsched
       
       */
       
      int jiq_read_sched(char *buf, char **start, off_t offset, int len, int
      unused)
       
      {

      {
       
          jiq_data.len = 0;               /* 还未打印,长度为0 */
       
          jiq_data.buf = buf;             /* 打印到这个缓冲区中 */
       
          jiq_data.jiffies = jiffies;     /* 开始时间 */
       
       
       
          /* jiq_print会调用 queue_task() 使自己重新进入 jiq_data.queue队列 */
       
          jiq_data.queue = &tq_scheduler;
       
       
       
          queue_task(&jiq_task, &tq_scheduler); /* 准备运行*/
       
          interruptible_sleep_on(&jiq_wait);    /* 进入睡眠队列只到任务完成 */
       
       
       
          return jiq_data.len;

          return jiq_data.len;
       
      }
       
       
       
      读读/proc/jiqsched文件很有意思,因为它显示调度器在何时运行-jiffies值表明调度
      器激活的时间。如果系统中有些正在占用CPU的进程,那么队列中各任务的运行间会有些
      延迟;因为调度器要在若干时钟滴答后才会抢先那些进程。打开这个文件会花上好几秒
      钟,因为它长达100行(在Alpha机器上是200行)。
       
       
       
      测试这些情形最简单方法是跑一个执行空循环的进程。load50是个增加机器负载的程序
      ,它在用户空间执行50个并发的忙循环;你可以在示例程序中找到它的源码(misc-progs
      /load50.c)。当在系统中运行load50程序时,head命令将从/proc/jiqsched文件中抽取
      类似如下的信息:
       
       
       
      time   delta     intr_count pid command
       
      1643733   0        0     701 head

      1643733   0        0     701 head
       
      1643747  14        0     658 load50
       
      1643747   0        0       3 kswapd
       
      1643755   8        0     655 load50
       
      1643761   6        0     666 load50
       
      1643764   3        0     650 load50
       
      1643767   3        0     661 load50
       
      1643769   2        0     659 load50
       
      1643769   0        0       6 loadmonitor
       
       
       
      注意到调度队列是在进入schedule过程后就执行的,因此current进程就是刚刚被调度出
      去的进程。这就是为什么/proc/jiqsched文件的第一行总是读该文件的那个进程;它正
      进入睡眠状态,就要被调出。还可以发现,kswapd和loadmonitor(这是我在我的系统上

      进入睡眠状态,就要被调出。还可以发现,kswapd和loadmonitor(这是我在我的系统上
      运行的一个程序)的执行时间都少于1个时钟滴答,而load50是在它的时间片耗尽后被抢
      先,这离它获得处理器有好几个时钟滴答。
       
       
       
      当系统中实际上没有任何进程在运行时,current进程总是空闲(idle)任务(0号进程,历
      史性的被称为"swapper"),任务队列或者是不断地运行或者是每隔1个时钟滴答运行一次
      。如果处理器不能进入“暂停”("halted")状态,调度器和任务队列就将不断运行;如
      果处理器能被0号进程暂停(halt),它们每隔1个时钟滴答才运行一次。暂停的(halted)
      处理器只能由中断唤醒。当中断发生时,空闲进程运行调度器(及相应的队列)。下面显
      示了在没有负载的系统运行运行命令head /proc/jiqsched得到的结果:
       
       
       
          time   delta     intr_count pid command
       
         1704475   0        0     730 head
       
         1704476   1        0       0 swapper
       
         1704477   1        0       0 swapper
       

       
         1704478   1        0       0 swapper
       
         1704478   0        0       6 loadmonitor
       
         1704479   1        0       0 swapper
       

⌨️ 快捷键说明

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