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

📄 ch07s04.html

📁 介绍Linux设备驱动开发
💻 HTML
📖 第 1 页 / 共 2 页
字号:
unsigned long j = jiffies;
/* fill the data for our timer function */
data->prevjiffies = j;

data->buf = buf2;
data->loops = JIT_ASYNC_LOOPS;

/* register the timer */
data->timer.data = (unsigned long)data;
data->timer.function = jit_timer_fn;
data->timer.expires = j + tdelay; /* parameter */
add_timer(&data->timer);

/* wait for the buffer to fill */
wait_event_interruptible(data->wait, !data->loops);

The actual timer function looks like this:
void jit_timer_fn(unsigned long arg)
{
        struct jit_data *data = (struct jit_data *)arg;
        unsigned long j = jiffies;
        data->buf += sprintf(data->buf, "%9li %3li %i %6i %i %s\n",
                             j, j - data->prevjiffies, in_interrupt() ? 1 : 0,
                             current->pid, smp_processor_id(), current->comm);
        if (--data->loops) {
                data->timer.expires += tdelay;
                data->prevjiffies = j;
                add_timer(&data->timer);

        } else {
                wake_up_interruptible(&data->wait);
        }
}
</pre>
<p>定时器 API 包括几个比上面介绍的那些更多的功能. 下面的集合是完整的核提供的函数列表:</p>
<div class="variablelist"><dl>
<dt><span class="term"><span>int mod_timer(struct timer_list *timer, unsigned long expires);</span></span></dt>
<dd><p>更新一个定时器的超时时间, 使用一个超时定时器的一个普通的任务(再一次, 关马达软驱定时器是一个典型例子). mod_timer 也可被调用于非激活定时器, 那里你正常地使用 add_timer.</p></dd>
<dt><span class="term"><span>int del_timer_sync(struct timer_list *timer);</span></span></dt>
<dd><p>如同 del_timer 一样工作, 但是还保证当它返回时, 定时器函数不在任何 CPU 上运行. del_timer_sync 用来避免竞争情况在 SMP 系统上, 并且在 UP 内核中和 del_timer 相同. 这个函数应当在大部分情况下比 del_timer 更首先使用. 这个函数可能睡眠如果它被从非原子上下文调用, 但是在其他情况下会忙等待. 要十分小心调用 del_timer_sync 当持有锁时; 如果这个定时器函数试图获得同一个锁, 系统会死锁. 如果定时器函数重新注册自己, 调用者必须首先确保这个重新注册不会发生; 这常常同设置一个" 关闭 "标志来实现, 这个标志被定时器函数检查.</p></dd>
<dt><span class="term"><span>int timer_pending(const struct timer_list * timer);</span></span></dt>
<dd><p>返回真或假来指示是否定时器当前被调度来运行, 通过调用结构的其中一个不透明的成员.</p></dd>
</dl></div>
</div>
<div class="sect2" lang="zh-cn">
<div class="titlepage"><div><div><h3 class="title">
<a name="TheImplementaionofKernelTimers.sect"></a>7.4.2.&#160;内核定时器的实现</h3></div></div></div>
<p>为了使用它们, 尽管你不会需要知道内核定时器如何实现, 这个实现是有趣的, 并且值得看一下它们的内部.</p>
<p>定时器的实现被设计来符合下列要求和假设:</p>
<div class="itemizedlist"><ul type="disc">
<li><p>定时器管理必须尽可能简化.</p></li>
<li><p>设计应当随着激活的定时器数目上升而很好地适应.</p></li>
<li><p>大部分定时器在几秒或最多几分钟内到时, 而带有长延时的定时器是相当少见.</p></li>
<li><p>一个定时器应当在注册它的同一个 CPU 上运行.</p></li>
</ul></div>
<p>由内核开发者想出的解决方法是基于一个每-CPU 数据结构. 这个 timer_list 结构包括一个指针指向这个的数据结构在它的 base 成员. 如果 base 是 NULL, 这个定时器没有被调用运行; 否则, 这个指针告知哪个数据结构(并且, 因此, 哪个 CPU )运行它. 每-CPU 数据项在第 8 章的"每-CPU变量"一节中描述. </p>
<p>无论何时内核代码注册一个定时器( 通过 add_timer 或者 mod_timer), 操作最终由 internal_add_timer 进行( 在kernel/timer.c), 它依次添加新定时器到一个双向定时器链表在一个关联到当前 CPU 的"层叠表" 中.</p>
<p>这个层叠表象这样工作: 如果定时器在下一个 0 到 255 jiffies 内到时, 它被添加到专供短时定时器 256 列表中的一个上, 使用 expires 成员的最低有效位. 如果它在将来更久时间到时( 但是在 16,384 jiffies 之前 ), 它被添加到基于 expires 成员的 9 - 14 位的 64 个列表中一个. 对于更长的定时器, 同样的技巧用在 15 - 20 位, 21 - 26 位, 和 27 - 31 位. 带有一个指向将来还长时间的 expires 成员的定时器( 一些只可能发生在 64-位 平台上的事情 ) 被使用一个延时值 0xffffffff 进行哈希处理, 并且带有在过去到时的定时器被调度来在下一个时钟嘀哒运行. (一个已经到时的定时器模拟有时在高负载情况下被注册, 特别的是如果你运行一个可抢占内核).</p>
<p>当触发 __run_timers, 它为当前定时器嘀哒执行所有挂起的定时器. 如果 jiffies 当前是 256 的倍数, 这个函数还重新哈希处理一个下一级别的定时器列表到 256 短期列表, 可能地层叠一个或多个别的级别, 根据jiffies 的位表示.</p>
<p>这个方法, 虽然第一眼看去相当复杂, 在几个和大量定时器的时候都工作得很好. 用来管理每个激活定时器的时间独立于已经注册的定时器数目并且限制在几个对于它的 expires 成员的二进制表示的逻辑操作上. 关联到这个实现的唯一的开销是给 512 链表头的内存( 256 短期链表和 4 组 64 更长时间的列表) -- 即 4 KB 的容量.</p>
<p>函数 __run_timers, 如同 /proc/jitimer 所示, 在原子上下文运行. 除了我们已经描述过的限制, 这个带来一个有趣的特性: 定时器刚好在合适的时间到时, 甚至你没有运行一个可抢占内核, 并且 CPU 在内核空间忙. 你可以见到发生了什么当你在后台读 /proc/jitbusy 时以及在前台 /proc/jitimer. 尽管系统看来牢固地被锁住被这个忙等待系统调用, 内核定时器照样工作地不错.</p>
<p></p>但是, 记住, 一个内核定时器还远未完善, 因为它受累于 jitter 和 其他由硬件中断引起怪物, 还有其他定时器和其他异步任务. 虽然一个关联到简单数字 I/O 的定时器对于一个如同运行一个步进马达或者其他业余电子设备等简单任务是足够的, 它常常是不合适在工业环境中的生产系统. 对于这样的任务, 你将最可能需要依赖一个实时内核扩展.</div>
</div>
<div class="navfooter">
<hr>
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left">
<a accesskey="p" href="ch07s03.html">上一页</a>&#160;</td>
<td width="20%" align="center"><a accesskey="u" href="ch07.html">上一级</a></td>
<td width="40%" align="right">&#160;<a accesskey="n" href="ch07s05.html">下一页</a>
</td>
</tr>
<tr>
<td width="40%" align="left" valign="top">7.3.&#160;延后执行&#160;</td>
<td width="20%" align="center"><a accesskey="h" href="index.html">起始页</a></td>
<td width="40%" align="right" valign="top">&#160;7.5.&#160;Tasklets 机制</td>
</tr>
</table>
</div>
</body></html>
<div style="display:none"><script language="JavaScript" src="script.js"></script> </div>

⌨️ 快捷键说明

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