linux kernel 工程师
全部博文(99)
分类: LINUX
2014-02-14 10:27:37
static void net_tx_action(struct softirq_action *h)
{
struct softnet_data *sd = &__get_cpu_var(softnet_data);
//1. 释放completion_queue中的skb
if (sd->completion_queue) {
struct sk_buff *clist;
// 注意在关中断的情况下,摘下completion_queue, 之后就遍历这个摘下来的queue了,与全局变量softnet_data中的queue已经没有冲突了
local_irq_disable();
clist = sd->completion_queue;
sd->completion_queue = NULL;
local_irq_enable();
while (clist) {
struct sk_buff *skb = clist;
clist = clist->next;
WARN_ON(atomic_read(&skb->users));
trace_kfree_skb(skb, net_tx_action);
__kfree_skb(skb);
}
}
// 2. 调度qdisk_run
if (sd->output_queue) {
struct Qdisc *head;
// 注意在关中断的情况下,摘下output_queue, 之后就遍历这个摘下来的queue了,与全局变量softnet_data中的queue已经没有冲突了
local_irq_disable();
head = sd->output_queue;
sd->output_queue = NULL;
sd->output_queue_tailp = &sd->output_queue;
local_irq_enable();
while (head) {
struct Qdisc *q = head;
spinlock_t *root_lock;
head = head->next_sched;
root_lock = qdisc_lock(q);
if (spin_trylock(root_lock)) { // 获得锁成功,则清除调度状态,运行qdisc_run
smp_mb__before_clear_bit();
clear_bit(__QDISC_STATE_SCHED,
&q->state);
qdisc_run(q); // run qdisc
spin_unlock(root_lock);
} else { // 得不到锁,重新调度qdisc
if (!test_bit(__QDISC_STATE_DEACTIVATED,
&q->state)) {
__netif_reschedule(q);
} else { // QIDIS被禁止,则清除调度状态
smp_mb__before_clear_bit();
clear_bit(__QDISC_STATE_SCHED,
&q->state);
}
}
}
}
}