免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 951 | 回复: 0
打印 上一主题 下一主题

include/linux中的interrupt.h [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-04-13 14:58 |只看该作者 |倒序浏览

                include/linux 中的interrupt.h中包含了与中断相关的大部分宏及struct结构的定义,以后有时间再一一说明
在2.6.12版的linux kernel中已经没有bottom half 和task
queue这两种机制,而是softirq,tasklet和work queue
,softirq主要是通过在每次中断返回是执行do_softirq这个函数完成,函数的主要部分是一个循环:
    do {
        if (pending & 1) {
            h->action(h);
            rcu_bh_qsctr_inc(cpu);
        }
        h++;
        pending >>= 1;
    } while (pending);
在最坏的情况下,这个循环会被执行10次,如果此时pending还是不为0,也就是说还有软中断没有处理,就唤醒一个内核线程去处理剩下的,这个线程叫
softirqd,每个cpu会有一个,所以如果执行ps
aux这条命令,会在某一行看到[softirqd/0],这个就是0号cpu的软中断守候线程。
tasklet实际上是两个软中断,为什么是两个呢?为了处理不同优先级的事情。这两个软中断一个的优先级高点,另一个的低一点。目前linux内核中已经用了6个软中断,这个在中有定义:
enum
{
    HI_SOFTIRQ=0,   优先级高点的tasklet
    TIMER_SOFTIRQ,    定时器
    NET_TX_SOFTIRQ,    发送网络数据
    NET_RX_SOFTIRQ,    接收网络数据
    SCSI_SOFTIRQ,    SCSI设备的软中断
    TASKLET_SOFTIRQ    优先级低的tasklet
};
这些数实际上是一个数,就是数组softirq_vec[32]的下标。
工作队列我不是很熟悉,这里就不说了,现在来对interrupt.h这个文件做一下注释吧
以下内容全部是从interrupt.h中拷贝出来的,并按原来的顺序排列,出于篇幅的考虑,减去了一些内容,以下的说明都是我认为很重要或者不好理解的部分。
typedef int irqreturn_t;
这个量及下面的三个宏都是为了可移植性,是中断处理函数的返回值,代码的作者有很详细的说明,可以直接看文件中的注释
#define IRQ_NONE    (0)
#define IRQ_HANDLED    (1)
#define IRQ_RETVAL(x)    ((x) != 0)
struct irqaction {
    irqreturn_t (*handler)(int, void *, struct pt_regs *);
    unsigned long flags;
    cpumask_t mask;
    const char *name;
    void *dev_id;
    struct irqaction *next;
    int irq;
    struct proc_dir_entry *dir;
};
这个结构就是中断处理程序很重要的结构了,这个就是在handle_IRQ_event(); 中处理的主要结构,用于执行真正的中断处理函数,
结构中handler是中断处理函数,你通过request_irq()
注册的函数,其实request_irq()传进来的参数就是用来填这个结构的,这个结构是一个单向链表,handle_IRQ_event()处理时是
遍历这个表
extern irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs);
这个是一个空函数,在kernel/irq/handle.c中,只有一句:return IRQ_NONE;
extern int request_irq(unsigned int,
      
       irqreturn_t (*handler)(int, void
*, struct pt_regs *),
               unsigned long, const char *, void *);
这个就是注册中断处理程序的函数,《linux kernel development》中有说明。
extern void free_irq(unsigned int, void *);
释放中断处理程序的函数,同上。
#ifdef CONFIG_GENERIC_HARDIRQS
extern void disable_irq_nosync(unsigned int irq);
extern void disable_irq(unsigned int irq);
extern void enable_irq(unsigned int irq);
#endif
这几个我还不知道是干什么的。
/*
* Temporary defines for UP kernels, until all code gets fixed.
*/
#ifndef CONFIG_SMP
一直到下面的#endif 都是开关cpu中断的指令的包装,实际上就是cli和sti和一些push和pop指令,这些在目录下用grep一下就出来了。
static inline void __deprecated cli(void)
{
    local_irq_disable();
}
static inline void __deprecated sti(void)
{
    local_irq_enable();
}
static inline void __deprecated save_flags(unsigned long *x)
{
    local_save_flags(*x);
}
#define save_flags(x) save_flags(&x);
static inline void __deprecated restore_flags(unsigned long x)
{
    local_irq_restore(x);
}
static inline void __deprecated save_and_cli(unsigned long *x)
{
    local_irq_save(*x);
}
#define save_and_cli(x)    save_and_cli(&x)
#endif /* CONFIG_SMP */
/* SoftIRQ primitives.  */
#define local_bh_disable() \
        do { add_preempt_count(SOFTIRQ_OFFSET); barrier(); } while (0)
#define __local_bh_enable() \
        do { barrier(); sub_preempt_count(SOFTIRQ_OFFSET); } while (0)
extern void local_bh_enable(void);
enum
{
    HI_SOFTIRQ=0,
    TIMER_SOFTIRQ,
    NET_TX_SOFTIRQ,
    NET_RX_SOFTIRQ,
    SCSI_SOFTIRQ,
    TASKLET_SOFTIRQ
};
这个就是前面提到的已经使用的软中断
/* softirq mask and active fields moved to irq_cpustat_t in
* asm/hardirq.h to get better cache usage.  KAO
*/
struct softirq_action
{
    void    (*action)(struct softirq_action *);
    void    *data;
};
这个就是软中断的结构,和硬中断的irqcation差不多的
asmlinkage void do_softirq(void);
这个不用说明,软中断的入口,这个函数在irq_exit()中被调用,如果有软中断要处理的话。
extern void open_softirq(int nr, void (*action)(struct
           
           
softirq_action*), void *data);
这个函数有于注册一个软中断,和request_irq()差不多。
extern void softirq_init(void);
#define __raise_softirq_irqoff(nr) do { local_softirq_pending() |= 1UL state);
}
static inline void tasklet_unlock(struct tasklet_struct *t)
{
    smp_mb__before_clear_bit();
    clear_bit(TASKLET_STATE_RUN, &(t)->state);
}
static inline void tasklet_unlock_wait(struct tasklet_struct *t)
{
    while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barrier(); }
}
#else
#define tasklet_trylock(t) 1
#define tasklet_unlock_wait(t) do { } while (0)
#define tasklet_unlock(t) do { } while (0)
#endif
extern void FASTCALL(__tasklet_schedule(struct tasklet_struct *t));
static inline void tasklet_schedule(struct tasklet_struct *t)
{
    if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
        __tasklet_schedule(t);
}
extern void FASTCALL(__tasklet_hi_schedule(struct tasklet_struct *t));
static inline void tasklet_hi_schedule(struct tasklet_struct *t)
{
    if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
        __tasklet_hi_schedule(t);
}
static inline void tasklet_disable_nosync(struct tasklet_struct *t)
{
    atomic_inc(&t->count);
    smp_mb__after_atomic_inc();
}
static inline void tasklet_disable(struct tasklet_struct *t)
{
    tasklet_disable_nosync(t);
    tasklet_unlock_wait(t);
    smp_mb();
}
static inline void tasklet_enable(struct tasklet_struct *t)
{
    smp_mb__before_atomic_dec();
    atomic_dec(&t->count);
}
static inline void tasklet_hi_enable(struct tasklet_struct *t)
{
    smp_mb__before_atomic_dec();
    atomic_dec(&t->count);
}
extern void tasklet_kill(struct tasklet_struct *t);
extern void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu);
extern void tasklet_init(struct tasklet_struct *t,
             void (*func)(unsigned long), unsigned long data);
/*
* Autoprobing for irqs:
*
* probe_irq_on() and probe_irq_off() provide robust primitives
* for accurate IRQ probing during kernel initialization.  They are
* reasonably simple to use, are not "fooled" by spurious interrupts,
* and, unlike other attempts at IRQ probing, they do not get hung on
* stuck interrupts (such as unused PS2 mouse interfaces on ASUS boards).
*
* For reasonably foolproof probing, use them as follows:
*
* 1. clear and/or mask the device's internal interrupt.
* 2. sti();
* 3. irqs = probe_irq_on();      // "take over" all unassigned idle IRQs
* 4. enable the device and cause it to trigger an interrupt.
* 5. wait for the device to interrupt, using non-intrusive polling or a delay.
* 6. irq = probe_irq_off(irqs);  // get IRQ number, 0=none, negative=multiple
* 7. service the device to clear its pending interrupt.
* 8. loop again if paranoia is required.
*
* probe_irq_on() returns a mask of allocated irq's.
*
* probe_irq_off() takes the mask as a parameter,
* and returns the irq number which occurred,
* or zero if none occurred, or a negative irq number
* if more than one irq occurred.
*/
#if defined(CONFIG_GENERIC_HARDIRQS) && !defined(CONFIG_GENERIC_IRQ_PROBE)
static inline unsigned long probe_irq_on(void)
{
    return 0;
}
static inline int probe_irq_off(unsigned long val)
{
    return 0;
}
static inline unsigned int probe_irq_mask(unsigned long val)
{
    return 0;
}
#else
extern unsigned long probe_irq_on(void);    /* returns 0 on failure */
extern int probe_irq_off(unsigned long);    /* returns 0 or negative on failure */
extern unsigned int probe_irq_mask(unsigned long);    /* returns mask of ISA interrupts */
#endif
#endif

               
               
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/16553/showart_99324.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP