SylixOS 中 select 原理及使用分析

1、select接口簡介

1.1 select接口使用用例

??select 是操作系統多路 I/O 復用技術實現的方式之一。

??select 函數允許程序監視多個文件描述符,等待所監視的一個或者多個文件描述符變為“準備好”的狀態。所謂的”準備好“狀態是指:文件描述符不再是阻塞狀態,可以用于某類 IO 操作了,包括可讀,可寫,發生異常三種。

??select 在應用中使用的例子如下段代碼所示。

#include <stdio.h>
#include <sys/select.h>int main (int argc, char *argv[])
{fd_set fdset;int ret;struct timeval timeout;char ch;timeout.tv_sec = 10;timeout.tv_usec = 0;for (;;) {FD_ZERO(&fdset);FD_SET(STDIN_FILENO, &fdset);ret = select(STDIN_FILENO + 1, &fdset, NULL, NULL, &timeout);if (ret <= 0) {break;} else if (FD_ISSET(STDIN_FILENO, &fdset)) {read(STDIN_FILENO, &ch, 1);if (ch == '\n') {continue;}fprintf(stdout, "input char: %c\n", ch);if (ch == 'q') {break;}}}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 內核中 select 實現

select 函數具體實現如下,主體可以分為 3 個部分:

  • 檢查讀文件集、寫文件集、異常文件集,調用 ioctl 的 FIOSELECT 命令
  • 調用 API_SemaphoreBPend 接口進行阻塞
  • 被喚醒后,調用 ioctl 的 FIOUNSELECT 命令
LW_API  
INT     pselect (INT                     iWidth, fd_set                 *pfdsetRead,fd_set                 *pfdsetWrite,fd_set                 *pfdsetExcept,const struct timespec  *ptmspecTO,const sigset_t         *sigsetMask)
{......if (pfdsetRead) {                                                   /*  檢查讀文件集                */selwunNode.SELWUN_seltypType = SELREAD;if (__selDoIoctls(&pselctx->SELCTX_fdsetOrigReadFds, pfdsetRead, iWidth, FIOSELECT, &selwunNode, LW_TRUE)) {                      /*  遇到錯誤,立即退出           */iIsOk = PX_ERROR;}}....../*  開始等待,這里是 select 阻塞的根源。 一般會在驅動的中斷處理函數中調用 wakeup_node ,去釋放這個二進制信號量   */ulError = API_SemaphoreBPend(pselctx->SELCTX_hSembWakeup,ulWaitTime);                            /*  開始等待                    */if (pfdsetRead) {                                                   /*  檢查讀文件集                */selwunNode.SELWUN_seltypType = SELREAD;if (__selDoIoctls(&pselctx->SELCTX_fdsetOrigReadFds, pfdsetRead, iWidth, FIOUNSELECT, &selwunNode, LW_FALSE)) {                     /*  如果存在節點,刪除節點       */iIsOk = PX_ERROR;}}......
}

??select 操作的一個重要數據結構,就是 “喚醒節點” ——LW_SEL_WAKEUPNODE

??select 函數允許程序監視多個文件描述符,這里的每一個文件描述符,對應一個“喚醒節點”。喚醒節點中一個重要的變量就是 SELWUN_hThreadId 線程 ID,記錄了創建該等待節點的線程句柄(其實就是調用 select 接口的線程)。該數據結構通過 ioctl 接口,傳遞到設備文件描述符對應的設備驅動中,由設備驅動去維護、管理該喚醒節點。

/*********************************************************************************************************等待節點類型
*********************************************************************************************************/typedef enum {SELREAD,                                                            /*  讀阻塞                      */SELWRITE,                                                           /*  寫阻塞                      */SELEXCEPT                                                           /*  異常阻塞                    */
} LW_SEL_TYPE;/*********************************************************************************************************等待鏈表節點.
*********************************************************************************************************/typedef struct {LW_LIST_LINE            SELWUN_lineManage;                          /*  管理鏈表                   */UINT32                  SELWUN_uiFlags;LW_OBJECT_HANDLE        SELWUN_hThreadId;                           /*  創建節點的線程句柄          */INT                     SELWUN_iFd;                                 /*  鏈接點的文件描述符          */LW_SEL_TYPE             SELWUN_seltypType;                          /*  等待類型                   */
} LW_SEL_WAKEUPNODE;
typedef LW_SEL_WAKEUPNODE  *PLW_SEL_WAKEUPNODE;    

2.2 設備驅動的 ioctl 實現

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

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

??驅動中 ioctl 的 FIOSELECT 實現,通常會調用 SEL_WAKE_NODE_ADD 接口,向設備驅動中添加一個“喚醒節點”(也可以把它理解成“等待節點”)。以 gpio 驅動為例:

static INT  _gpiofdSelect (PLW_GPIOFD_FILE  pgpiofdfil, PLW_SEL_WAKEUPNODE   pselwunNode)
{......SEL_WAKE_NODE_ADD(&pgpiofdfil->GF_selwulist, pselwunNode);......
}static INT  _gpiofdUnselect (PLW_GPIOFD_FILE  pgpiofdfil, PLW_SEL_WAKEUPNODE   pselwunNode)
{......SEL_WAKE_NODE_DELETE(&pgpiofdfil->GF_selwulist, pselwunNode);......
}static INT  _gpiofdIoctl (PLW_GPIOFD_FILE pgpiofdfil, INT             iRequest, LONG            lArg)
{......switch (iRequest) {......case FIOSELECT:pselwunNode = (PLW_SEL_WAKEUPNODE)lArg;return  (_gpiofdSelect(pgpiofdfil, pselwunNode));case FIOUNSELECT:pselwunNode = (PLW_SEL_WAKEUPNODE)lArg;return  (_gpiofdUnselect(pgpiofdfil, pselwunNode));}......
}

節點的組織形式如下:

  • 設備驅動相關結構體中,會維護一個指針,指向喚醒節點鏈表(這個鏈表由設備驅動去維護)
  • 鏈表節點的添加,是調用SEL_WAKE_NODE_ADD 函數完成的

在這里插入圖片描述

2.3 阻塞與喚醒實現

阻塞
??select 本身是一個阻塞函數。通過調用二進制信號量 API_SemaphoreBPend,實現阻塞操作。

注意,這里的二進制信號量,實際上是一個同步信號量。在調用 pend 之前,pselect 會首先調用 ioctl,傳遞 FIOSELECT 參數。此接口中會判斷 當前 是否滿足 select 的喚醒條件,若滿足則先調用 post,以使之后調用的 pend 不會被阻塞; 若 當前 不滿足 select 的喚醒條件,則會進入阻塞狀態,等待設備驅動主動去喚醒

喚醒
??通常是由 select 所監聽的文件描述符集對應的設備驅動去喚醒。還是以 gpio 驅動為例,當一個 gpio 中斷(電平觸發、邊沿觸發)產生時,就會告訴操作系統,該 gpio 的狀態“可讀”,通過調用 SEL_WAKE_UP_ALL 接口實現喚醒操作。該接口底層實現,實際上就是調用 API_SemaphoreBPost

LW_API  
VOID    API_SelWakeup (PLW_SEL_WAKEUPNODE   pselwunNode)
{
....../*  根據喚醒節點中保存的線程 ID,獲取線程 TCB 結構  */usIndex = _ObjectGetIndex(pselwunNode->SELWUN_hThreadId);ptcb = __GET_TCB_FROM_INDEX(usIndex);if (!ptcb || !ptcb->TCB_pselctxContext) {                           /*  線程不存在                  */return;}/*  設置喚醒節點的 READY 屬性 */LW_SELWUN_SET_READY(pselwunNode);/*  根據 TCB,找到需要喚醒的句柄 SELCTX_hSembWakeup  */pselctxContext = ptcb->TCB_pselctxContext;API_SemaphoreBPost(pselctxContext->SELCTX_hSembWakeup);             /*  提前激活即將等待線程        */
}static irqreturn_t  _gpiofdIsr (PLW_GPIOFD_FILE pgpiofdfil)
{
......SEL_WAKE_UP_ALL(&pgpiofdfil->GF_selwulist, SELREAD);
......
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/74659.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/74659.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/74659.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring WebFlux之ServerWebExchange

ServerWebExchange 是 Spring WebFlux 中的一個核心接口&#xff0c;用于表示服務器端處理的 HTTP 請求和響應。它封裝了請求和響應的所有信息&#xff0c;并提供了相應的方法來操作這些信息。ServerWebExchange 在響應式編程模型中扮演著關鍵角色&#xff0c;支持非阻塞、異步…

Flutter 常見錯誤和坑

1. 狀態管理問題 StatefulWidget 生命周期誤用 // 錯誤&#xff1a;在 build 方法中修改狀態 override Widget build(BuildContext context) {setState(() { counter; }); // 會導致無限重建循環return Text($counter); }// 正確&#xff1a;在事件處理中修改狀態 Widget bui…

C++智能指針萬字詳細講解(包含智能指針的模擬實現)

在筆試&#xff0c;面試中智能指針經常出現&#xff0c;如果你對智能指針的作用&#xff0c;原理&#xff0c;用法不了解&#xff0c;那么可以看看這篇博客講解&#xff0c;此外本博客還簡單模擬實現了各種指針&#xff0c;在本篇的最后還應對面試題對智能指針的知識點進行了拓…

【Go】Go語言結構體筆記

整體介紹 雖然 Go 語言不是傳統意義上的面向對象語言&#xff0c;但它提供了結構體&#xff08;struct&#xff09;來組織數據&#xff0c;并且可以為結構體綁定方法&#xff0c;從而達到面向對象的部分效果。 關鍵知識點包括&#xff1a; 結構體定義與實例化 定義結構體時使用…

Three.js 快速入門教程【十八】射線拾取模型——鼠標點擊屏幕選中模型或物體

系列文章目錄 Three.js 快速入門教程【一】開啟你的 3D Web 開發之旅 Three.js 快速入門教程【二】透視投影相機 Three.js 快速入門教程【三】渲染器 Three.js 快速入門教程【四】三維坐標系 Three.js 快速入門教程【五】動畫渲染循環 Three.js 快速入門教程【六】相機控件 Or…

Object.defineProperty()Proxy詳解(Vue23數據劫持實現)

底層原理&#x1f447;&#x1f3ff; 總結一下&#xff0c;結構應該包括&#xff1a; 1. 方法的基本作用和參數。 2. 數據描述符和存取描述符的區別。 3. 屬性定義的內部處理流程。 4. 在Vue中的應用實例。 5. 常見錯誤和正確實踐。 每個部分都要結合搜索結果的信息&…

MySQL 進階語法:函數、約束、多表查詢、事務

目錄 一、MySQL 常用函數 1. 字符串函數 1.1 基本字符串操作 1.2 字符串截取與處理 1.3 字符串搜索與替換 2. 數值函數 2.1 基本數學運算 2.2 數學計算 2.3 隨機數與符號 3. 日期時間函數 3.1 獲取當前時間 3.2 日期時間計算 3.3 日期時間提取 3.4 日期時間格式化…

第 12 章(番外)| Solidity 安全前沿趨勢 × 審計生態 × 職業路徑規劃

&#x1f310; 第 12 章&#xff08;番外&#xff09;| Solidity 安全前沿趨勢 審計生態 職業路徑規劃 ——做得了審計&#xff0c;也接得了項目&#xff0c;走進 Web3 安全工程師的職業實戰地圖 ? 本章導讀 Solidity 安全&#xff0c;不只是代碼安全、業務安全、審計安全…

1、pytest基本用法

目錄 先給大家分享下學習資源 1. 安裝pytest 2. 編寫用例規則 3. 執行用例 最近在學習pytest的用法 并且用這套框架替換了原來的unittest&#xff0c; 同是測試框架 確實感覺到pytest更加便捷 這邊分享給大家我得學習心得 先給大家分享下學習資源 1 官方文檔 pytest 官方…

【sylar-webserver】5 協程調度模塊

文章目錄 設計思路三種協程的切換 協程調度模塊&#xff0c;需要把前面的線程模塊和協程模塊結合使用 ~ 設計思路 構造函數定義 線程池 基本信息。start()&#xff0c;創建線程池&#xff0c;每個線程創建都執行 run()。每個線程在 run() 里&#xff0c;查找任務隊列 m_tasks…

Go 語言規范學習(1)

文章目錄 IntroductionNotation示例&#xff08;Go 語言的 if 語句&#xff09;&#xff1a; Source code representationCharacters例子&#xff1a;變量名可以是中文 Letters and digits Lexical elementsCommentsTokensSemicolons例子&#xff1a;查看程序所有的token Ident…

探索抓包利器ProxyPin,實現手機APP請求抓包,支持https請求

以下是ProxyPin的簡單介紹&#xff1a; - ProxyPin是一個開源免費HTTP(S)流量捕獲神器&#xff0c;支持 Windows、Mac、Android、IOS、Linux 全平臺系統- 可以使用它來攔截、檢查并重寫HTTP(S)流量&#xff0c;支持捕獲各種應用的網絡請求。ProxyPin基于Flutter開發&#xff0…

深度學習3-pytorch學習

深度學習3-pytorch學習 Tensor 定義與 PyTorch 操作 1. Tensor 定義&#xff1a; Tensor 是 PyTorch 中的數據結構&#xff0c;類似于 NumPy 數組。可以通過不同方式創建 tensor 對象&#xff1a; import torch# 定義一個 1D Tensor x1 torch.Tensor([3, 4])# 定義一個 Fl…

深入淺出Spring-Boot-3.x.pdf

通過網盤分享的文件&#xff1a;深入淺出Spring-Boot-3.x.pdf 鏈接: https://pan.baidu.com/s/10ZkhmeIXphEwND9Rv4EBlg?pwduatm 提取碼: uatm

springboot啟動事件CommandLineRunner使用

什么是CommandRunner CommandRunner是springboot啟動完成時會調用的一個runner 啟動參數會傳遞到這個runner 我們能用來做一些初始化工作和緩存預熱等工作 ApplicationRunner VS CommandRunner? 這兩個Runner作用一樣 只是得到的啟動參數格式不一樣 前者是一個Argument對象…

數據可視化TensorboardX和tensorBoard安裝及使用

tensorBoard 和TensorboardX 安裝及使用指南 tensorBoard 和 TensorBoardX 是用于可視化機器學習實驗和模型訓練過程的工具。TensorBoard 是 TensorFlow 官方提供的可視化工具&#xff0c;而 TensorBoardX 是其社區驅動的替代品&#xff0c;支持 PyTorch 等其他框架。以下是它…

藍橋杯C++基礎算法-多重背包

這段代碼實現了一個多重背包問題的動態規劃解法。多重背包問題與完全背包問題類似&#xff0c;但每個物品有其數量限制。以下是代碼的詳細思路解析&#xff1a; 1. 問題背景 給定 n 個物品&#xff0c;每個物品有其體積 v[i]、價值 w[i] 和數量 s[i]&#xff0c;以及一個容量為…

【SUNO】【AI作詞】【提示詞】

仿寫歌詞提示詞模板&#xff08;升級版&#xff09; 一、仿寫目標 風格定位 音樂風格&#xff1a; [填寫目標風格&#xff0c;如&#xff1a;民謠/流行/古風/電子/爵士等]參考案例&#xff1a;如《成都》的敘事民謠&#xff0c;《孤勇者》的勵志流行。 情感基調&#xff1a; […

26考研——樹與二叉樹_樹與二叉樹的應用(5)

408答疑 文章目錄 三、樹與二叉樹的應用哈夫曼樹和哈夫曼編碼哈夫曼樹的定義概念帶權路徑長度&#xff08;WPL&#xff09;計算示例分析 哈夫曼樹的構造算法描述哈夫曼樹的性質示例 哈夫曼編碼Huffman樹的編碼規則Huffman樹的構建過程前綴編碼前綴編碼的分析及應用 Huffman樹的…

【VUE】day06 動態組件 插槽 自定義指令 ESlint

【VUE】day06 動態組件 & 插槽 & 自定義指令 1. 動態組件1.1 通過不同的按鈕展示不同的組件1.1.1回顧click 1.2 keep-alive的使用1.3 keep-alive對應的生命周期函數1.3.1 keep-alive的include屬性1.3.2 exclude 1.4 組件注冊名稱和組件聲明時name的區別1.4.1 組件聲明時…