DPDK(15):DPDK中斷機制簡析

轉自:http://www.cnblogs.com/MerlinJ/p/4104039.html 

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 to
11      * 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 handling\n");
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 function
10          */
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 instance\n");
21 
22         pipe_event.data.fd = intr_pipe.readfd;
23         /**
24          * add pipe fd into wait list, this pipe is used to
25          * 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, %s\n",
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 descriptor
44              * 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, %s\n",
49                     src->intr_handle.fd, strerror(errno));
50             }
51             else
52                 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 the
60          * 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鏈表中,方便中斷處理線程遍歷調用。

 

 

錯誤之處,歡迎指出。

轉載請標明轉自http://www.cnblogs.com/MerlinJ/p/4104039.html 


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 to
11      * 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 handling\n");
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 function
10          */
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 instance\n");
21 
22         pipe_event.data.fd = intr_pipe.readfd;
23         /**
24          * add pipe fd into wait list, this pipe is used to
25          * 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, %s\n",
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 descriptor
44              * 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, %s\n",
49                     src->intr_handle.fd, strerror(errno));
50             }
51             else
52                 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 the
60          * 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鏈表中,方便中斷處理線程遍歷調用。

 

 

錯誤之處,歡迎指出。

轉載請標明轉自http://www.cnblogs.com/MerlinJ/p/4104039.html 

發佈了24 篇原創文章 · 獲贊 8 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章