DPDK中断机制总结

DPDK通过在线程中使用epoll模型,监听UIO设备的事件,来模拟操作系统的中断处理。

一、中断初始化
在rte_eal_intr_init()函数中初始化中断。具体如下:
1、首先初始化intr_sources链表。所有UIO设备的中断都挂在这个链表上,中断处理线程通过遍历这个链表,来执行设备的中断。
2、创建intr_pipe管道,用于epoll模型的消息通知。
3、创建线程intr_thread,线程的执行体是eal_intr_thread_main()函数,创建epoll模型,遍历intr_sources链表,监听已注册的所有UIO设备的中断事件,并调用对应UIO设备的中断处理函数。

  int
  rte_eal_intr_init(void)
  {
      int ret = 0;
  
       /* init the global interrupt source head */
      TAILQ_INIT(&intr_sources);
  
      /**
      * create a pipe which will be waited by epoll and notified to
      * rebuild the wait list of epoll.
      */
     if (pipe(intr_pipe.pipefd) < 0)
         return -1;
 
     /* create the host thread to wait/handle the interrupt */
     ret = pthread_create(&intr_thread, NULL,
            eal_intr_thread_main, NULL);
     if (ret != 0)
        RTE_LOG(ERR, EAL,
             "Failed to create thread for interrupt handling\n");
 
     return -ret;
}

中断线程执行主体eal_intr_thread_main()函数具体如下:
1、epoll_create()创建epoll模型。
2、将intr_pipe管道加入到epoll中。
3、遍历intr_sources链表,将所有UIO设备加入到epoll中。
4、在eal_intr_handle_interrupts()函数中,在一个for(;;)死循环中,调用epoll_wait()阻塞模式监听事件。如果有事件发生,则调用eal_intr_process_interrupts()函数,最终会调用到相应UIO设备注册的中断处理函数。

  static __attribute__((noreturn)) void *
  eal_intr_thread_main(__rte_unused void *arg)
  {
      struct epoll_event ev;
  
      /* host thread, never break out */
      for (;;) {
          /* build up the epoll fd with all descriptors we are to
          * wait on then pass it to the handle_interrupts function
          */
         static struct epoll_event pipe_event = {
             .events = EPOLLIN | EPOLLPRI,
        };
         struct rte_intr_source *src;
         unsigned numfds = 0;
 
         /* create epoll fd */
         int pfd = epoll_create(1);
         if (pfd < 0)
             rte_panic("Cannot create epoll instance\n");
 
         pipe_event.data.fd = intr_pipe.readfd;
         /**
         * add pipe fd into wait list, this pipe is used to
         * rebuild the wait list.
          */
         if (epoll_ctl(pfd, EPOLL_CTL_ADD, intr_pipe.readfd,
                         &pipe_event) < 0) {
             rte_panic("Error adding fd to %d epoll_ctl, %s\n",
                    intr_pipe.readfd, strerror(errno));
        }
         numfds++;
 
         rte_spinlock_lock(&intr_lock);
 
         TAILQ_FOREACH(src, &intr_sources, next) {
             if (src->callbacks.tqh_first == NULL)
                 continue; /* skip those with no callbacks */
             ev.events = EPOLLIN | EPOLLPRI;
             ev.data.fd = src->intr_handle.fd;
 
             /**
             * add all the uio device file descriptor
             * into wait list.
              */
             if (epoll_ctl(pfd, EPOLL_CTL_ADD,
                     src->intr_handle.fd, &ev) < 0){
                 rte_panic("Error adding fd %d epoll_ctl, %s\n",
                     src->intr_handle.fd, strerror(errno));
            }
             else
                 numfds++;
        }
         rte_spinlock_unlock(&intr_lock);
         /* serve the interrupt */
        eal_intr_handle_interrupts(pfd, numfds);
 
         /**
         * when we return, we need to rebuild the
         * list of fds to monitor.
          */
        close(pfd);
    }
 }

二、中断注册
以e1000网卡为例说明。在网卡初始化的时候,会调用rte_eth_dev_init()—>eth_igb_dev_init()—>rte_intr_callback_register()注册中断处理函数。

 rte_intr_callback_register(&(pci_dev->intr_handle),
 eth_igb_interrupt_handler, (void *)eth_dev);

rte_intr_callback_register()函数,主要工作如下:
1、首先申请一个struct rte_intr_source变量。

struct rte_intr_source {
    TAILQ_ENTRY(rte_intr_source) next;
    struct rte_intr_handle intr_handle; /**< interrupt handle */
    struct rte_intr_cb_list callbacks;  /**< user callbacks */
    uint32_t active;
 };

2、将中断处理函数eth_igb_interrupt_handler,添加到rte_intr_source->callbacks链表中。
3、再将该rte_intr_source挂到全局intr_sources链表中,方便中断处理线程遍历调用。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值