网络子系统20_传输接收软中断

来源:互联网 发布:mpii数据集 编辑:程序博客网 时间:2024/06/03 21:01
//数据帧接收软中断处理函数//调用路径:do_softirq->net_rx_action//函数主要任务://1.在关中断情况下检查调度队列poll_list是否有设备接收到入口帧,然后开中断//2.单次运行处理的入口帧不能超过netdev_max_backlog=300,运行时间不能超过1个jiffies//3.依次遍历调度队列poll_list//4.如果设备配额以用完,或者设备驱动的poll函数表明仍然有入口数据帧//4.1 将设备重新添加poll_list尾部,重新分配配额,准备接受下一次调度//5.如果单次运行没有调度完所有接收到入口帧的设备,则再次设置接受软中断调度标志,退出//注:接收软中断中,poll_list上挂载的npai设备,或者非napi设备使用的积压设备。3.2 static void net_rx_action(struct softirq_action *h){struct softnet_data *queue = &__get_cpu_var(softnet_data);unsigned long start_time = jiffies;int budget = netdev_max_backlog;//关本地中断local_irq_disable();//有设备有输入流量while (!list_empty(&queue->poll_list)) {struct net_device *dev;//执行时间超过了一个1 jiffies//或者本次软中断处理的输入流量已经超过了netdev_max_backlog,退出软中if (budget <= 0 || jiffies - start_time > 1)goto softnet_break;local_irq_enable();//获得设备指针dev = list_entry(queue->poll_list.next, struct net_device, poll_list);//如果设备的配额已经用完,或者执行一次poll之后,此设备依然有待处理的流量if (dev->quota <= 0 || dev->poll(dev, &budget)) {local_irq_disable();//将设备从list上删除,添加到list尾部list_del(&dev->poll_list);list_add_tail(&dev->poll_list, &queue->poll_list);//给设备重新分配配额,已weight作为一次分配的量,范围从1024~64if (dev->quota < 0)dev->quota += dev->weight;elsedev->quota = dev->weight;} else {dev_put(dev);local_irq_disable();}}out:local_irq_enable();return;softnet_break:__get_cpu_var(netdev_rx_stat).time_squeeze++;//重新调度接收软中断__raise_softirq_irqoff(NET_RX_SOFTIRQ);goto out;}//发送软中断处理函数//一次处理output_queue中所有等待传输的设备//调用路径:do_softirq->net_tx_action//函数主要功能://1.释放本cpu所有已经完成传输的skb//2.关中断的情况获取本cpu的传输设备队列output_queue, 其中的设备有数据需要进行传输//3.清除设备传输调度标志,表明设备可以接收下一次传输调度//4.获取设备队列锁queue_lock,通过队列规则接口,进行设备数据传输//5.如果获取queue_lock失败,说明设备当前正在进行传输,重调度设备//注:发送软中断中,output_queue挂载的设备均为有队列规则设备,没有队列规则的设备不会在软中断进行传输,因为其没有传输调度的概念3.3 static void net_tx_action(struct softirq_action *h){struct softnet_data *sd = &__get_cpu_var(softnet_data);//如果完成队列非空if (sd->completion_queue) {struct sk_buff *clist;//关本cpu中断local_irq_disable();//取下本cpu的完成队列clist = sd->completion_queue;sd->completion_queue = NULL;local_irq_enable();while (clist) {struct sk_buff *skb = clist;clist = clist->next;//释放对应的skb__kfree_skb(skb);}}//如果输出队列非空if (sd->output_queue) {struct net_device *head;//将输出队列取下local_irq_disable();head = sd->output_queue;sd->output_queue = NULL;local_irq_enable();while (head) {struct net_device *dev = head;//net_device 通过next_sched链接到output_queue上head = head->next_sched;//一个内存屏障smp_mb__before_clear_bit();//设备准备好进行传输,清除设备调度标志,说明,当设备执行传输时,属于非调度状态,可以被重新调度。clear_bit(__LINK_STATE_SCHED, &dev->state);//获取设备的输出队列锁if (spin_trylock(&dev->queue_lock)) {//通过出口队列规则,调度设备qdisc_run(dev);spin_unlock(&dev->queue_lock);} else {//说明队列正在进行传输,重新调度设备netif_schedule(dev);}}}}

原创粉丝点击