SylixOS 之epoll異常分析

1. SylixOS epoll介紹

    SylixOS爲了兼容Linux的epoll,創建了epoll的兼容子系統,並支持了epoll的部分功能。SylixOS epoll兼容子系統是由select子系統模擬出來的,所以效率沒有select高。

2. epoll異常分析

2.1epoll異常場景

    在使用線程A創建AF_UNIX匿名套接字發送數據;線程B把套接字加入epoll監聽,且設置屬性爲一次有效;線程C等待epoll事件產生,並讀取套接字中的數據。如程序清單 2-1所示。

                                       程序清單 2-1
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/epoll.h>
#define READSIZE           7
int     iEfd            =  0;
int     iFd[2]          = {0};

void *send_data (void *arg)
{
    int iRet   =   0;
    /*
     * 使用socketpair函數創造一對未命名的、相互連接的UNIX域套接字
     * 並且的在一端不斷的發送數據
     */
    iRet = socketpair(AF_UNIX, SOCK_STREAM, 0, iFd);
    if (iRet < 0) {
    perror("socketpair");
    return NULL;
    }
    for (;;) {
        write(iFd[0], "SylixOS", READSIZE);
        sleep(1);
    }
}

void *test_ctl(void *arg)
{
    struct epoll_event    event;
    int                   iRet  = 0;
    while (1) {
    / *
      * 把套接字加入epoll監聽,且設置監聽屬性爲一次有效
      */
        event.events  = 0;
        event.events  = EPOLLIN | EPOLLONESHOT;
        event.data.fd  = iFd[1];
        iRet = epoll_ctl(iEfd, EPOLL_CTL_MOD, iFd[1], &event);
        if (iRet == 0) {
            printf("test_ctl ctl ok\n");
        }
    sleep(1);
   }
}

void *test_wait(void *arg)
{
    struct epoll_event event;
    int                iRet            = 0;
    char               cBuf[READSIZE] = {0};
    while (1) {
    / *
      * 使用epoll等待事件,並讀取數據。讀取結束後等待下一次事件產生
      */ 
    iRet = epoll_wait(iEfd, &event, 1, -1);
    if (iRet == 1) {
        printf("test_wait event.data.fd is %d event.events is %x\n",
        event.data.fd,event.events);
        read(iFd[1], cBuf, READSIZE);
    }
    sleep(1);
    }
}
int main(int argc, char **argv)
{
    pthread_t             send_tid,
                          wait_tid,
                          ctl_tid;
    int                   iRet     = 0;
    struct epoll_event    event;
    /*
     *  創建一個 epoll 文件描述符
     */
    iEfd = epoll_create(10);
    if (0 == iEfd) {
        perror("epoll create");
        return (-1);
    }
    iRet = pthread_create(&send_tid, NULL, &send_data, NULL);
    if (iRet != 0) {
        fprintf(stderr, "pthread create failed.\n");
        return (-1);
    }
    sleep(1);
    / *
      * 把套接字加入epoll監聽,且設置爲一次有效
      */
    event.events  = EPOLLIN | EPOLLONESHOT;
    event.data.fd = iFd[1];
    iRet = epoll_ctl(iEfd, EPOLL_CTL_ADD, iFd[1], &event);
    if (iRet != 0) {
        perror("epoll_ctl");
        return (-1);
    }
    iRet = pthread_create(&wait_tid, NULL, &test_wait, NULL);
    if (iRet != 0) {
        perror("pthread create");
        return (-1);
    }
    iRet = pthread_create(&ctl_tid, NULL, &test_ctl, NULL);
    if (iRet != 0) {
        perror("pthread create");
        return (-1);
    }
    pthread_join(send_tid, NULL);
    pthread_join(wait_tid, NULL);
    pthread_join(ctl_tid, NULL);
    return (0);
}

    該程序運行時,運行結果如圖 2-1所示。

wKioL1m-eduAMTFNAABswrssWO0194.png

 

圖 2-1 運行結果

    此時線程test_wait阻塞等待事件產生,根據程序清單 2-1所示,send_data線程一直在寫入數據,同時test_ctl線程也在把事件加入epoll中監聽。

2.2epoll異常分析

    SylixOS epoll兼容子系統是由select子系統模擬出來的,分析epoll_wait源碼。epoll_wait代碼框架如圖 2-2所示。

wKioL1m-ek2gtCfXAABT-RY_jcE119.png 

圖 2-2 epoll_wait流程

    根據epoll_wait實現流程可以發現,如果在epoll_ctl設置事件屬性爲一次有效,在epoll_wait後事件屬性置空。如果此刻epoll_wait在下次epoll_ctl操作之前使用,那麼epoll_wait中監聽的文件描述符集合即爲空(因爲事件屬性爲空),所以select一直處於監聽,且沒有事件產生。

3. epoll異常總結

    把程序清單 2-1中設置保證epoll_wait在epoll_ctl之後運行,運行結果如圖 3-1所示。

wKiom1m-esLBHa0TAABecPyt0y8962.png 

圖 3-1 運行結果

    在SylixOS上使用epoll功能需要注意要保證epoll_wait在epoll_ctl設置之後使用,這樣保證epoll_wait監聽的文件描述符集合不爲空。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章