📄 interrupts.html
字号:
<span class="coMULTI">/* update the timer code missing */</span> write_sequnlock<span class="br0">(</span>&xtime_lock<span class="br0">)</span>; <span class="kw1">return</span> IRQ_HANDLED; <span class="br0">}</span></pre><p>The arguments for the interrupt handler are: </p><ul><li class="level1"><div class="li"> Interrupt number</div></li><li class="level1"><div class="li"> Private data structure (used for shared interrupts)</div></li><li class="level1"><div class="li"> contents of stack before the interrupt occurred.</div></li></ul><p>The interrupt handler must return a 1 to indicate that the interrupt has been processed.</p></div><!-- SECTION [28011-30465] --><h2><a name="linux_interrupt_actions" id="linux_interrupt_actions">Linux Interrupt Actions</a></h2><div class="level2"><p> This section deals with what you can do with an interrupt during the service call. The system is in an interrupt service state and normally only a limited number of options are available. If a fast interrupt is being serviced the interrupt routine is being run with interrupts disabled. This means that any lengthy processing should be avoided to prevent degrading the system.</p><p>Here is a short list of options available during an interrupt service routine. </p><ul><li class="level1"><div class="li"> Reset the interrupting device</div></li><li class="level1"><div class="li"> Pend a bottom half</div></li><li class="level1"><div class="li"> Wake up a sleeping task</div></li><li class="level1"><div class="li"> Trigger a tasklet</div></li></ul></div><!-- SECTION [30466-31068] --><h3><a name="resetting_the_source" id="resetting_the_source">Resetting the Source</a></h3><div class="level3"><p> This normally means resetting a timer or reading a register to remove the source of an interrupt. This is especially important in the case of a level triggered interrupt to prevent the system delivering on stop interrupts.</p></div><!-- SECTION [31069-31322] --><h3><a name="pending_a_bottom_half" id="pending_a_bottom_half">Pending a Bottom Half</a></h3><div class="level3"><p> The bottom half is a traditional way of splitting a service between fast service tasks done with interrupts disabled and slower tasks that need to be done in kernel context but before resuming “normal” processing. There are a fixed number of bottom halves slots (32) and just about all of them have been allocated to historical tasks. The one remaining bottom half task is the one related to running the immediate task queue. This queue is run on the return from interrupt, any return from a system call or any time the scheduler is called.</p><p>Before spending a lot of time on this please note that this service has been replaced by the tasklet system. A reference is included to allow you to understand any legacy code.</p><p>The following code example will show you how to trigger the immediate BH from an interrupt service routine. </p><pre class="code c"> <span class="co2">#include <linux/tqueue.h> </span> <span class="co2">#include <linux/interrupt.h> </span> <span class="kw4">static</span> <span class="kw4">struct</span> tq_struct some_tq; <span class="kw4">void</span> some_handler <span class="br0">(</span> <span class="kw4">unsigned</span> <span class="kw4">long</span> some_data <span class="br0">)</span> <span class="br0">{</span> <span class="coMULTI">/* do whatever */</span> <span class="br0">}</span> <span class="kw4">void</span> some_interrupt<span class="br0">(</span><span class="kw4">int</span> irq , <span class="kw4">void</span> * dev_id , <span class="kw4">struct</span> pt_regs * regs<span class="br0">)</span> <span class="br0">{</span> <span class="kw4">unsigned</span> <span class="kw4">long</span> some_data; <span class="coMULTI">/* turn off the interrupt */</span> some_tq.<span class="me1">routine</span> = some_handler; some_tq.<span class="me1">data</span> = some_data; queue_task<span class="br0">(</span>&some_tq, &tq_immediate<span class="br0">)</span>; mark_bh<span class="br0">(</span>IMMEDIATE_BH<span class="br0">)</span>; <span class="br0">}</span></pre><p> The new (in Kernel 2.6) workqueue interface.. </p><pre class="code c"> <span class="co2">#include <linux/workqueue.h> // NEW for Kernel 2.6 </span> <span class="co2">#include <linux/interrupt.h> </span> <span class="kw4">void</span> my_work_fn <span class="br0">(</span> <span class="kw4">unsigned</span> <span class="kw4">long</span> some_data <span class="br0">)</span> <span class="br0">{</span> <span class="coMULTI">/* do whatever */</span> <span class="br0">}</span> <span class="kw4">unsigned</span> <span class="kw4">long</span> some_data; <span class="kw4">static</span> DECLARE_WORK<span class="br0">(</span>my_work, my_work_fn, some_data<span class="br0">)</span>; irqreturn_t some_interrupt<span class="br0">(</span><span class="kw4">int</span> irq , <span class="kw4">void</span> * dev_id , <span class="kw4">struct</span> pt_regs * regs<span class="br0">)</span> <span class="br0">{</span> schedule_work<span class="br0">(</span>&my_work<span class="br0">)</span>; <span class="br0">}</span></pre></div><!-- SECTION [31323-35392] --><h3><a name="wake_up_a_sleeping_task" id="wake_up_a_sleeping_task">Wake up a Sleeping Task</a></h3><div class="level3"><p> Another option inside an interrupt service routine is to wake up a sleeping task. The task will enter an interruptible_sleep_on and wait to be woken up by the wake up call in the interrupt service routine.</p><p>Another code example helps: </p><pre class="code c"> <span class="co2">#include <linux/wait.h> </span> <span class="co2">#include <linux/interrupt.h> </span> <span class="kw4">static</span> DECLARE_WAIT_QUEUE_HEAD<span class="br0">(</span>my_waitqueue<span class="br0">)</span>; <span class="kw4">static</span> <span class="kw4">int</span> cond = <span class="nu0">0</span>; <span class="kw4">void</span> some_task<span class="br0">(</span><span class="kw4">unsigned</span> <span class="kw4">long</span> some_data<span class="br0">)</span> <span class="br0">{</span> <span class="kw4">int</span> done = <span class="nu0">0</span>; <span class="kw1">while</span><span class="br0">(</span>!done<span class="br0">)</span> <span class="br0">{</span> wait_event_interruptible<span class="br0">(</span>my_waitqueue,<span class="br0">(</span>cond == <span class="nu0">0</span><span class="br0">)</span><span class="br0">)</span>; <span class="coMULTI">/* do whatever */</span> <span class="br0">}</span> <span class="br0">}</span> irqreturn_t some_interrupt<span class="br0">(</span><span class="kw4">int</span> irq , <span class="kw4">void</span> * dev_id , <span class="kw4">struct</span> pt_regs * regs<span class="br0">)</span> <span class="br0">{</span> <span class="coMULTI">/* turn off the interrupt */</span> cond = <span class="nu0">1</span>; wake_up_interruptible<span class="br0">(</span>&my_waitqueue<span class="br0">)</span>; <span class="kw1">return</span> <span class="nu0">1</span>; <span class="br0">}</span></pre></div><!-- SECTION [35393-37884] --><h3><a name="run_a_tasklet" id="run_a_tasklet">Run a Tasklet</a></h3><div class="level3"><p> This is the favored option with the 2.4 kernels. They can be scheduled many times and are guaranteed to be run once on the CPU they were first scheduled on. However several different tasklets may be scheduled to run at one time. Semaphores cannot be used to protect critical regions, you have to use spinlocks.</p><p>A Tasklet code example follows:</p><pre class="code c"> <span class="co2">#include <linux/tqueue.h> </span> <span class="co2">#include <linux/interrupt.h> </span> <span class="kw4">void</span> some_task<span class="br0">(</span><span class="kw4">unsigned</span> <span class="kw4">long</span><span class="br0">)</span>; <span class="kw4">unsigned</span> <span class="kw4">long</span> some_data; DECLARE_TASKLET<span class="br0">(</span>some_name, some_task, some_data<span class="br0">)</span>; <span class="kw4">void</span> some_task <span class="br0">(</span> <span class="kw4">unsigned</span> <span class="kw4">long</span> some_data <span class="br0">)</span> <span class="br0">{</span> <span class="coMULTI">/* do whatever */</span> <span class="br0">}</span> <span class="kw4">void</span> some_interrupt<span class="br0">(</span><span class="kw4">in
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -