SylixOS中select原理及使用分析
阿新 • • 發佈:2018-02-27
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不會被阻塞。
其流程如下圖所示。
3.2 喚醒操作
在需要進行喚醒的地方調用SEL_WAKE_UP系列接口,如產生中斷的地方、檢測的線程中。
SylixOS中select原理及使用分析