首页 > 编程知识 正文

DPDK 中断机制 ealintrhandleinterrupts,dma接口内有中断机制

时间:2023-05-04 00:42:18 阅读:268182 作者:3431

转自:http://blog.csdn.net/xy010902100449/article/details/47283147

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设备的中断处理函数。

1 int 2 rte_eal_intr_init(void) 3 { 4 int ret = 0; 5 6 /* init the global interrupt source head */ 7 TAILQ_INIT(&intr_sources); 8 9 /**10 * create a pipe which will be waited by epoll and notified to11 * rebuild the wait list of epoll.12 */13 if (pipe(intr_pipe.pipefd) < 0)14 return -1;15 16 /* create the host thread to wait/handle the interrupt */17 ret = pthread_create(&intr_thread, NULL,18 eal_intr_thread_main, NULL);19 if (ret != 0)20 RTE_LOG(ERR, EAL,21 "Failed to create thread for interrupt handlingn");22 23 return -ret;24 }

中断线程执行主体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设备注册的中断处理函数。

1 static __attribute__((noreturn)) void * 2 eal_intr_thread_main(__rte_unused void *arg) 3 { 4 struct epoll_event ev; 5 6 /* host thread, never break out */ 7 for (;;) { 8 /* build up the epoll fd with all descriptors we are to 9 * wait on then pass it to the handle_interrupts function10 */11 static struct epoll_event pipe_event = {12 .events = EPOLLIN | EPOLLPRI,13 };14 struct rte_intr_source *src;15 unsigned numfds = 0;16 17 /* create epoll fd */18 int pfd = epoll_create(1);19 if (pfd < 0)20 rte_panic("Cannot create epoll instancen");21 22 pipe_event.data.fd = intr_pipe.readfd;23 /**24 * add pipe fd into wait list, this pipe is used to25 * rebuild the wait list.26 */27 if (epoll_ctl(pfd, EPOLL_CTL_ADD, intr_pipe.readfd,28 &pipe_event) < 0) {29 rte_panic("Error adding fd to %d epoll_ctl, %sn",30 intr_pipe.readfd, strerror(errno));31 }32 numfds++;33 34 rte_spinlock_lock(&intr_lock);35 36 TAILQ_FOREACH(src, &intr_sources, next) {37 if (src->callbacks.tqh_first == NULL)38 continue; /* skip those with no callbacks */39 ev.events = EPOLLIN | EPOLLPRI;40 ev.data.fd = src->intr_handle.fd;41 42 /**43 * add all the uio device file descriptor44 * into wait list.45 */46 if (epoll_ctl(pfd, EPOLL_CTL_ADD,47 src->intr_handle.fd, &ev) < 0){48 rte_panic("Error adding fd %d epoll_ctl, %sn",49 src->intr_handle.fd, strerror(errno));50 }51 else52 numfds++;53 }54 rte_spinlock_unlock(&intr_lock);55 /* serve the interrupt */56 eal_intr_handle_interrupts(pfd, numfds);57 58 /**59 * when we return, we need to rebuild the60 * list of fds to monitor.61 */62 close(pfd);63 }64 }

 

 二、中断注册

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

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

rte_intr_callback_register()函数,主要工作如下:

1、首先申请一个struct rte_intr_source变量。

1 struct rte_intr_source {2 TAILQ_ENTRY(rte_intr_source) next;3 struct rte_intr_handle intr_handle; /**< interrupt handle */4 struct rte_intr_cb_list callbacks; /**< user callbacks */5 uint32_t active;6 };

2、将中断处理函数eth_igb_interrupt_handler,添加到rte_intr_source->callbacks链表中。

3、再将该rte_intr_source挂到全局intr_sources链表中,方便中断处理线程遍历调用。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。