Linux中断之softirq和tasklet

软中断

代码位置:/kernel/softirq.c
软中断和中断是非常类似的,它最大的不同的就是使用软件来实现的。

数据结构

<interrupt.h>
struct softirq_action
{
void (*action)(struct softirq_action *);
};

代码分析

软中断的操作过程
1.注册软中断的处理函数

void open_softirq(int nr, void (*action)(struct softirq_action *)) 
{
    softirq_vec[nr].action = action;
}

2.软中断的触发方式:

  • 在中断上下文中调用raise_softirq(int nr)。
void raise_softirq(unsigned int nr) 
{
    unsigned long flags;

    /* 这个和具体的处理器架构相关 */
    local_irq_save(flags);
    raise_softirq_irqoff(nr);
    local_irq_restore(flags);
}
  • 调用wakeup_softirqd来唤醒软中断守护进程。
static void wakeup_softirqd(void)
{
    /* Interrupts are disabled: no need to stop preemption */
    struct task_struct *tsk = __this_cpu_read(ksoftirqd);

    if (tsk && tsk->state != TASK_RUNNING)
        wake_up_process(tsk);
}

3.关闭软中断,其中nr为系统分配的软中断号。

inline void raise_softirq_irqoff(unsigned int nr)
{
    __raise_softirq_irqoff(nr);

    /*
     * If we're in an interrupt or softirq, we're done
     * (this also catches softirq-disabled code). We will
     * actually run the softirq once we return from
     * the irq or softirq.
     *
     * Otherwise we wake up ksoftirqd to make sure we
     * schedule the softirq soon.
     */
    if (!in_interrupt())
        wakeup_softirqd();
}

另外还有个比较重要的函数:

void __init softirq_init(void) 
{
    int cpu;

    for_each_possible_cpu(cpu) {
        per_cpu(tasklet_vec, cpu).tail =
            &per_cpu(tasklet_vec, cpu).head;
        per_cpu(tasklet_hi_vec, cpu).tail =
            &per_cpu(tasklet_hi_vec, cpu).head;
    }   

    open_softirq(TASKLET_SOFTIRQ, tasklet_action);
    open_softirq(HI_SOFTIRQ, tasklet_hi_action);
}

tasklet

大多数的情况下使用tasklet就可以了,只有在net这样的高要求条件下采用softirq。而tasklet就是利用softirq来实现的。从下面的枚举量中可以看出:

enum
{
    HI_SOFTIRQ=0,
    TIMER_SOFTIRQ, 
    NET_TX_SOFTIRQ,
    NET_RX_SOFTIRQ,
    BLOCK_SOFTIRQ,
    IRQ_POLL_SOFTIRQ,
    TASKLET_SOFTIRQ,
    SCHED_SOFTIRQ,
    HRTIMER_SOFTIRQ, /* Unused, but kept as tools rely on the numbering. Sigh! */
    RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */

    NR_SOFTIRQS
};

数据结构

struct tasklet_struct
{
    struct tasklet_struct *next;	//用于形成链表
    unsigned long state;
    atomic_t count;
    void (*func)(unsigned long);	//具体的处理函数
    unsigned long data;
};

代码分析

1.定义一个tasklet。

最终都是调用的下面这个函数:

void tasklet_init(struct tasklet_struct *t,
          void (*func)(unsigned long), unsigned long data)
{
    t->next = NULL;
    t->state = 0;
    atomic_set(&t->count, 0);           
    t->func = func;
    t->data = data;                     
}

2.编写tasklet的处理函数。
void tasklet_handler(unsigned long data)
注意:因为是softirq实现的,所以不能睡眠。不能使用信号量或者其它的阻塞方式。
3.调度tasklet,比如:

static inline void tasklet_schedule(struct tasklet_struct *t) 
{
    if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
        __tasklet_schedule(t);
}

其中:

void __tasklet_schedule(struct tasklet_struct *t)
{   
    unsigned long flags;

    local_irq_save(flags);
    t->next = NULL;
    *__this_cpu_read(tasklet_vec.tail) = t;
    __this_cpu_write(tasklet_vec.tail, &(t->next));
    raise_softirq_irqoff(TASKLET_SOFTIRQ);
    local_irq_restore(flags);
}

tasklet禁止和使能:

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(); 
    atomic_dec(&t->count);
}

另外在SMP中会用到的函数:

static inline int tasklet_trylock(struct tasklet_struct *t) 
{
    return !test_and_set_bit(TASKLET_STATE_RUN, &(t)->state);
}

static inline void tasklet_unlock(struct tasklet_struct *t) 
{
    smp_mb__before_atomic();
    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(); }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值