SylixOS中select原理及使用分析

1. select接口簡介

1.1 select接口使用用例

select是操作系統多路I/O複用技術實現的方式之一。
多路I/O複用技術大致使用場景爲:構造一張感興趣的文件描述符列表,然後調用多路複用的IO接口,在接口中進行阻塞,直到這些描述符中的一個已準備好進行I/O時,該函數才返回。
select在應用中使用的例子如下段代碼所示。

#include <sys/select.h>
int main (int argc, char **argv)
{  
    fd_set       fdset;
    struct timeval  timeout;

    timeout.tv_sec  = 10;
    timeout.tv_usec = 0;

    int fd = open("/dev/htm2", O_RDWR, 0666);

    for (;;) {
        FD_ZERO(&fdset);
        FD_SET(fd, &fdset);
        select(fd + 1, &fdset, &fdset, NULL, &timeout);
        sleep(1);
    }
    return  (0);
}

1.2 select函數原型分析

LW_API INT   select(INT                   iWidth, 
                   fd_set               *pfdsetRead,
                   fd_set               *pfdsetWrite,
                   fd_set               *pfdsetExcept,
                   struct timeval        *ptmvalTO);
  • iWidth爲設置的文件集中,最大的文件號 + 1;
  • pfdsetRead爲關心的可讀文件集;
  • pfdsetWrite爲關心的可寫文件集;
  • pfdsetExcept爲關心的異常文件集;
  • ptmvalTO爲等待超時時間,LW_NULL表示永遠等待。
  • 返回值:正常返回等待到的文件數量,錯誤返回 PX_ERROR。

2. 驅動中的select實現

2.1 驅動的ioctl實現

SylixOS的select接口實現中,系統會調用到每一個fd對應的設備驅動的ioctl接口,並會調用到如下表所示的兩個命令。

命令 說明
FIOSELECT 添加SEL_WAKE_NODE節點
FIOUNSELECT 移除SEL_WAKE_NODE節點

2.2 SylixOS的select等待鏈

添加與移除SEL_WAKE_NODE的操作實際都是對SylixOS的select等待鏈進行操作,
對應調用如SEL_WAKE_NODE_ADD與SEL_WAKE_NODE_DELETE的系統接口。
等待鏈的作用就是將一堆阻塞待喚醒的線程組成集合,當需要被喚醒時可以通過調用系統的SEL_WAKE_UP系列函數實現對線程的喚醒。
SylixOS提供的喚醒命令如下表所示。

命令 說明
SEL_WAKE_UP 喚醒一個等待線程
SEL_WAKE_UP_ALL 喚醒等待某一類型操作的所有線程
SEL_WAKE_UP_TYPE 獲取節點的等待類型
SEL_WAKE_UP_ERROR 由於產生了錯誤,喚醒一個等待的線程
SEL_WAKE_UP_TERM 由於產生了錯誤,喚醒所有等待某一類型操作的所有線程

2.3 SylixOS中的select上下文

需要注意的是:select阻塞操作使用的信號量爲select上下文之中的,並不需要在驅動的FIOSELECT裏再實現一個信號量。
select的上下文如下段程序所示。

typedef struct {
    LW_OBJECT_HANDLE       SELCTX_hSembWakeup;              /*  喚醒信號量              */
    BOOL                   SELCTX_bPendedOnSelect;          /*  是否阻塞在 select() 上  */
    fd_set                *SELCTX_pfdsetReadFds;            /*  阻塞的讀文件集指針       */
    fd_set                *SELCTX_pfdsetWriteFds;           /*  阻塞的寫文件集指針       */
    fd_set                *SELCTX_pfdsetExceptFds;          /*  阻塞的異常文件集指針     */
    fd_set                 SELCTX_fdsetOrigReadFds;         /*  原始的讀文件集          */
    fd_set                 SELCTX_fdsetOrigWriteFds;        /*  原始的寫文件集          */
    fd_set                 SELCTX_fdsetOrigExceptFds;       /*  原始的異常文件集        */
    INT                    SELCTX_iWidth;                   /*  select() 第一個參數    */
} LW_SEL_CONTEXT;
typedef LW_SEL_CONTEXT     *PLW_SEL_CONTEXT;

3. 阻塞與喚醒實現

3.1 阻塞操作

select的阻塞操作是在其內部調用的pselect函數中調用二進制信號量的pend操作實現的。但是在調用pend之前,pselect會首先調用ioctl,傳遞FIOSELECT參數,此接口中會判斷當前是否滿足select的喚醒條件,若滿足則先調用post,以使之後調用的pend不會被阻塞。
其流程如下圖所示。

select內核處理原理

3.2 喚醒操作

在需要進行喚醒的地方調用SEL_WAKE_UP系列接口,如產生中斷的地方、檢測的線程中。

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