/***********************Linux-2.6.32************************************/ //include/linux/hardirq.h in_irq() //CPU正服务于硬件中断时,返回True in_softirq() //CPU正服务于软件中断时,返回True in_interrupt() //CPU正在服务于一个硬件中断或软件中断,或抢占功能关闭时,返回True //arch/x86/include/asm/hardirq.h local_softirq_pending() //本地CPU至少有一个IRQ出于未决状态时,返回True //include/linux/interrupt.h __raise_softirq_irqoff() //设置与软IRQ相关联的标识,将IRQ标记为未决 raise_softirq_irqoff() //__raise_softirq_irqoff包裹函数,当in_interrupt为False时,唤醒ksoftirqd raise_softirq() //包裹raise_softirq_irqoff,调用raise_softirq_irqoff前先关中断 //kernel/softirq.c __local_bh_enable() //开启本地CPU的下半部 local_bh_enable() //如果有任何软IRQ未决,且in_interrupt返回False,则invoke_softirq local_bh_disable() //关闭CPU下半部 //include/linux/irqflags.h local_irq_enable() //开启本地CPU中断功能 local_irq_disable() //关闭本地CPU中断功能 local_irq_save() //先把本地CPU中断状态保存,再予以关闭 local_irq_restore() //恢复本地CPU之前的中断状态,恢复local_irq_save保存的中断信息 //include/linux/spinlock.h spin_lock_bh() //取得回旋锁,关闭下半部及抢占功能 spin_unlock_bh() //释放回旋锁,重启下半部抢占功能
//inculde/linux/preempt.h
preempt_disable() //为当前任务关闭抢占功能。可重复调用,递增引用计数器
preempt_enable() //抢占功能再度开启,(需要先检查引用计数器是否为0)
preempt_enable_no_resch() //递减引用计数器,只有引用计数器为0时,抢占功能才能再度开启
preempt_check_resched() //由preempt_enable调用,检查引用计数器是否为0.
// arch/x86/include/asm/thread_info.h
struct thread_info {
……
int preempt_count; /* 0 => preemptable,
<0 => BUG */ //抢占计数器,指定进程是否能被抢占
……
};enum {
TIMER_BH = 0,
CONSOLE_BH,
TQUEUE_BH,
DIGI_BH,
SERIAL_BH,
RISCOM8_BH,
SPECIALIX_BH,
AURORA_BH,
ESP_BH,
NET_BH, //网络下半部
SCSI_BH,
IMMEDIATE_BH,
KEYBOARD_BH,
CYCLADES_BH,
CM206_BH,
JS_BH,
MACSERIAL_BH,
ISICOM_BH
};_ _initfunc(int net_dev_init(void))
{
... ... ...
init_bh(NET_BH, net_bh);
... ... ...
}extern inline void mark_bh(int nr)
{
set_bit(nr, &bh_active);
};skb_queue_tail(&backlog, skb); mark_bh(NET_BH); return
//include/linux/interrupt.h
enum
{
HI_SOFTIRQ=0, //高优先级微任务
TIMER_SOFTIRQ,
NET_TX_SOFTIRQ, //网络软IRQ
NET_RX_SOFTIRQ, //网络软IRQ
BLOCK_SOFTIRQ,
BLOCK_IOPOLL_SOFTIRQ,
TASKLET_SOFTIRQ, //低优先级微任务软IRQ
SCHED_SOFTIRQ,
HRTIMER_SOFTIRQ,
RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */
NR_SOFTIRQS
}; /*
* Incoming packets are placed on per-cpu queues so that
* no locking is needed.
*/
struct softnet_data
{
struct Qdisc *output_queue; //qdisc是queueing discipline的简写,也就是排队规则,即qos.这里也就是输出帧的控制。
struct sk_buff_head input_pkt_queue; //当输入帧被驱动取得之前,就保存在这个队列里,(不适用与napi驱动,napi有自己的私有队列)
struct list_head poll_list; //表示有输入帧待处理的设备链表。
struct sk_buff *completion_queue; //表示已经成功被传递出的帧的链表。
struct napi_struct backlog; //用来兼容非napi的驱动。
};static int __init net_dev_init(void)
{
......
for_each_possible_cpu(i) {
struct softnet_data *queue;
queue = &per_cpu(softnet_data, i);
skb_queue_head_init(&queue->input_pkt_queue);
queue->completion_queue = NULL;
INIT_LIST_HEAD(&queue->poll_list);
queue->backlog.poll = process_backlog;
queue->backlog.weight = weight_p;
queue->backlog.gro_list = NULL;
queue->backlog.gro_count = 0;
}
......
}// kernel/softirq.c
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
softirq_vec[nr].action = action;
}__raise_softirq_irqoff() //设置与软IRQ相关联的标识,将IRQ标记为未决 raise_softirq_irqoff() //__raise_softirq_irqoff包裹函数,当in_interrupt为False时,唤醒ksoftirqd raise_softirq() //包裹raise_softirq_irqoff,调用raise_softirq_irqoff前先关中断
/*
* Tasklets
*/
struct tasklet_head
{
struct tasklet_struct *head;
struct tasklet_struct **tail;
};
static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);
static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);struct tasklet_struct
{
struct tasklet_struct *next; //把关联到同一个CPU的结构链接起来
unsigned long state; //位图标识,其可能的取值由TASKLET_STATE_XXX枚举
atomic_t count; //计数器,0表示微任务被关闭,不可执行。非0表示微任务已经开启
void (*func)(unsigned long); //要执行的函数
unsigned long data; //上面函数的参数
};
enum
{
TASKLET_STATE_SCHED, /* Tasklet is scheduled for execution */
TASKLET_STATE_RUN /* Tasklet is running (SMP only) */
};原文地址:http://blog.csdn.net/windeal3203/article/details/44457001