【補充】Linux內核鏈表機制


專題文章:Linux內核鏈表與Pinctrl數據結構解析

目標: 深入解析Pinctrl子系統中,struct pinctrl如何通過內核鏈表,來組織和管理其多個struct pinctrl_state

1. 問題背景:一個設備,多種引腳狀態

一個復雜的設備,例如一個現代WiFi/藍牙二合一模塊,在不同的工作模式下,對引腳的要求是不同的。我們假設它有四種狀態,并在設備樹中進行了如下聲明:

// 在wifi_bt.dts中
&wifi_bt {...pinctrl-names = "default",      // (A) 高速數據傳輸狀態"idle",         // (B) 低功耗空閑狀態"sleep",        // (C) 深度睡眠狀態"bt_sco";       // (D) 藍牙語音通話狀態pinctrl-0 = <&wifi_pins_default>;pinctrl-1 = <&wifi_pins_idle>;pinctrl-2 = <&wifi_pins_sleep>;pinctrl-3 = <&bt_sco_pins>;...
};

當內核解析這個設備時,它需要在內存中為wifi_bt設備建立一個數據結構,來清晰地管理這四種引腳狀態(A, B, C, D)以及它們對應的具體配置。

2. 核心數據結構:pinctrlpinctrl_state

內核使用兩個核心結構體來完成這個管理任務:

  • struct pinctrl (總管):
    • 這是為wifi_bt設備創建的一個總的Pinctrl信息管理器
    • 關鍵成員:
      struct pinctrl {// (P) ... 其他成員 ...// (Q) 一個鏈表頭,是所有狀態的“集合點”struct list_head states; // ... 其他成員 ...
      };
      
  • struct pinctrl_state (具體狀態):
    • 每一種引腳狀態(如"default"、“idle”)都對應一個這樣的結構體實例。
    • 關鍵成員:
      struct pinctrl_state {// (R) 狀態的名字const char *name;// (S) 一個鏈表頭,用于存放此狀態下的具體配置指令struct list_head settings; // (T) 一個鏈表節點,是把自己“掛”到總管鏈表上的“鉤子”struct list_head node;     
      };
      
3. 組織方式:嵌入式鏈表

Linux內核不把struct pinctrl_state本身直接串起來,而是通過它們內部的node成員(T)來建立連接。struct pinctrl里的states成員(Q)就是這個鏈表的“頭結點”或“錨點”。

可視化數據結構關系:

   (wifi_bt設備的總管: struct pinctrl)
+--------------------------------------------+
| (P) ...                                    |
| (Q) states: [ next ]---------------------->|  (指向A的node)
| ...                                        |
+--------------------------------------------+^| (D的node指向Q,形成閉環)|
+---------------------------------------------------------------------------------------------+
|                                                                                             |
|   (A) pinct-state "default"    (B) pinct-state "idle"     (C) pinct-state "sleep"    (D) pinct-state "bt_sco" |
|  +------------------------+   +------------------------+   +------------------------+   +------------------------+ |
|  | (R) name="default"     |   | (R) name="idle"        |   | (R) name="sleep"       |   | (R) name="bt_sco"      | |
|  | (S) settings: [ ... ]  |   | (S) settings: [ ... ]  |   | (S) settings: [ ... ]  |   | (S) settings: [ ... ]  | |
|  | (T) node: [ next ]---->|-->| (T) node: [ next ]---->|-->| (T) node: [ next ]---->|-->| (T) node: [ next ]-----|
|  +------------------------+   +------------------------+   +------------------------+   +------------------------+ |
|                                                                                             |
+---------------------------------------------------------------------------------------------+

關系解讀:

  • pinctrl->states (Q) 是鏈表的起點和終點,它形成了一個環。
  • 它不直接指向pinctrl_state結構體(A, B, C, D)的開頭。
  • 它指向的是下一個元素的node成員(T)。比如,從(Q)出發,可以找到(A)的node成員。從(A)的node成員,可以找到(B)的node成員,以此類推,最后(D)的node成員會指回(Q),形成閉環。
4. 核心操作:如何通過node找到state

這是理解的關鍵。當內核需要查找名為"idle"的狀態時,它會遍歷這個由node成員組成的鏈表。

  • 遍歷: 內核代碼會從pinctrl->states(Q)開始,沿著next指針逐個訪問(A)、(B)、?、(D)的node成員(T)。
  • 獲取node指針: 在遍歷過程中,比如當它訪問到(B)的node成員時,它得到一個指向struct list_head的指針,我們稱之為node_ptr
  • 反向計算 (使用list_entry宏):
    • 已知信息:
      1. node_ptrnode成員在內存中的確切地址。
      2. struct pinctrl_statenode成員所在的外部大結構體的類型。
      3. nodenode成員在struct pinctrl_state這個類型定義中的名字。
    • 計算邏輯: 整個結構體的起始地址 = 成員的地址 - 成員在結構體內的偏移量。
    • 內核的實現: list_entry(node_ptr, struct pinctrl_state, node)這個宏會執行上述計算,并返回一個指向struct pinctrl_state的指針。在這個例子中,它會返回(B)這個pinctrl_state結構體的起始地址。
  • 比較與返回: 內核拿到pinctrl_state的指針后,就可以訪問它的name成員?,與目標字符串"idle"進行比較。如果匹配,查找成功。
5. 結論
  • pinctrl_state中的node成員(T),是該狀態實例能夠被鏈表管理的**“連接件”**。
  • pinctrl中的states成員(Q),是所有狀態實例的**“組織者”**和鏈表的入口。
  • 內核通過遍歷由node組成的鏈表,并利用list_entry宏進行地址反向計算,來高效地查找和訪問任何一個具體的pinctrl_state實例。這種“侵入式”設計是Linux內核中一種通用且高效的數據組織模式。

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

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

相關文章

本地部署Dify、Docker重裝

需要先安裝一個Docker&#xff0c;Docker就像是一個容器&#xff0c;將部署Dify的空間與本地環境隔離&#xff0c;避免因為本地環境的一些問題導致BUG。也確保了環境的統一&#xff0c;不會出現在自己的電腦上能跑但是移植到別人電腦上就跑不通的情況。那么現在就開始先安裝Doc…

【每天一個知識點】非參聚類(Nonparametric Clustering)

ChatGPT 說&#xff1a;“非參聚類”&#xff08;Nonparametric Clustering&#xff09;是一類不預先設定聚類數目或數據分布形式的聚類方法。與傳統“參數聚類”&#xff08;如高斯混合模型&#xff09;不同&#xff0c;非參聚類在建模過程中不假設數據來自于已知分布數量的某…

人形機器人CMU-ASAP算法理解

一原文在第一階段&#xff0c;用重定位的人體運動數據在模擬中預訓練運動跟蹤策略。在第二階段&#xff0c;在現實世界中部署策略并收集現實世界數據來訓練一個增量&#xff08;殘差&#xff09;動作模型來補償動態不匹配。&#xff0c;ASAP 使用集成到模擬器中的增量動作模型對…

next.js刷新頁面時二級菜單展開狀態判斷

在 Next.js 中保持二級菜單刷新后展開狀態的解決方案 在 Next.js 應用中&#xff0c;當頁面刷新時保持二級菜單的展開狀態&#xff0c;可以通過以下幾種方法實現&#xff1a; 方法1&#xff1a;使用 URL 參數保存狀態&#xff08;推薦&#xff09; import { useRouter } from n…

網絡基礎DAY13-NAT技術

NAT技術internet接入方式&#xff1a;ADLS技術&#xff1a;能夠將不同設備的不同信號通過分離器進行打包之后再internet中傳輸&#xff0c;到另一端的分離器之后再進行分離。傳輸到不同的設備中去。常見光纖接入方式internet接入認證方式&#xff1a;PPPoE&#xff1a;先認證再…

HBuilderX中設置 DevEco Studio路徑,但是一直提示未安裝

前言&#xff1a; HBuilderX中設置 DevEco Studio路徑&#xff0c;但是一直提示未安裝。 報錯信息&#xff1a; 檢測到鴻蒙工具鏈&#xff0c;請在菜單“工具->設置->運行配置”中設置鴻蒙開發者工具路徑為 DevEco Studio 的安裝路徑&#xff0c;請參考 報錯原因…

什么是GNN?——聚合、更新與循環

在傳統的深度學習中&#xff0c;卷積神經網絡&#xff08;CNN&#xff09;擅長處理網格結構數據&#xff08;如圖像&#xff09;&#xff0c;循環神經網絡&#xff08;RNN&#xff09;擅長處理序列數據&#xff08;如文本&#xff09;。但當數據以圖的形式存在時&#xff08;如…

深入解析 Django REST Framework 的 APIView 核心方法

在 Python 3 中&#xff0c;Django 的 APIView 類是 Django REST Framework&#xff08;DRF&#xff09;中用于構建 API 視圖的核心基類。它提供了一個靈活的框架來處理 HTTP 請求&#xff0c;并通過一系列方法支持認證、權限檢查和請求限制等功能。self.perform_authenticatio…

神經網絡——卷積層

目錄 卷積層介紹 Conv2d 卷積動畫演示 卷積代碼演示 綜合代碼案例 卷積層介紹 卷積層是卷積神經網絡&#xff08;CNN&#xff09;的核心組件&#xff0c;它通過卷積運算提取輸入數據的特征。 基本原理 卷積層通過卷積核&#xff08;過濾器&#xff09;在輸入數據&…

神經網絡——線性層

在機器學習中&#xff0c;線性層&#xff08;Linear Layer&#xff09; 是一種基礎的神經網絡組件&#xff0c;也稱為全連接層&#xff08;Fully Connected Layer&#xff09; 或密集層&#xff08;Dense Layer&#xff09;。 其嚴格的數學定義為&#xff1a;對輸入數據執行線…

大模型高效適配:軟提示調優 Prompt Tuning

The Power of Scale for Parameter-Efficient Prompt Tuning ruatishi 軟提示向量 具體是什么 《The Power of Scale for Parameter-Efficient Prompt Tuning》中增加的部分是“軟提示(soft prompts)”,這是一種針對特定下游任務,添加到輸入文本中的可調參數序列。它與傳統…

https正向代理 GoProxy

背景&#xff1a; 在安全隔離的內網環境中&#xff0c;部署于內網的應用如需調用公網第三方接口&#xff08;如支付、短信&#xff09;&#xff0c;可通過正向代理服務實現訪問。 GoProxy 下載&#xff1a; https://github.com/snail007/goproxy/releases 使用文檔&#xff…

Java IO流體系詳解:字節流、字符流與NIO/BIO對比及文件拷貝實踐

一、字節流與字符流&#xff1a;如何選擇&#xff1f; 1.1 核心區別特性字節流字符流處理單位字節&#xff08;8位&#xff09;字符&#xff08;16位Unicode&#xff09;適用場景二進制文件&#xff08;圖片/視頻&#xff09;文本文件&#xff08;TXT/CSV&#xff09;編碼處理需…

QT6 源,七章對話框與多窗體(5) 文件對話框 QFileDialog 篇二:源碼帶注釋

&#xff08;13&#xff09;本源代碼定義于頭文件 qfiledialog . h &#xff1a; #ifndef QFILEDIALOG_H #define QFILEDIALOG_H#include <QtWidgets/qtwidgetsglobal.h> #include <QtCore/qdir.h> #include <QtCore/qstring.h> #include <QtCore/qurl.h…

關于Ajax的學習筆記

Ajax概念&#xff1a;是一門使用了js語言&#xff0c;可以使用于Javaweb&#xff0c;實現前端代碼和后端代碼連結的的一種異步同步&#xff08;不需要等待服務器相應&#xff0c;就能夠發送第二次請求&#xff09;的一種技術&#xff0c;它主要用于網頁內容的局部刷新&#xff…

The Missing Semester of Your CS Education 學習筆記以及一些拓展知識(三)

文章目錄The Missing Semester of Your CS Education 學習筆記以及一些拓展知識Vim編輯器筆記部分程序員常用的編輯器Vim的模式Vim的普通模式Vim的插入模式Vim的可視模式Vim的替換模式Vim的命令行模式Vim的高級功能文本對象宏寄存器緩沖區標記代碼折疊Vim的常用配置Vim的常用插…

PyTorch常用的簡單數學運算

一、基礎算術運算1. 逐元素運算a torch.tensor([1, 2, 3]) b torch.tensor([4, 5, 6])# 加減乘除 a b # [5, 7, 9] a - b # [-3, -3, -3] a * b # [4, 10, 18] a / b # [0.25, 0.4, 0.5]# 冪運算、平方根 a ** 2 # [1, 4, 9] torch.sqrt(a) # [1.0, 1.414, 1.732]2. 標…

C++ Lambda 表達式詳解:從基礎到實戰

Lambda 表達式是 C11 引入的重要特性&#xff0c;它允許我們在代碼中定義匿名函數&#xff0c;極大地簡化了代碼編寫&#xff0c;尤其是在使用 STL 算法和多線程編程時。本文將詳細介紹 Lambda 表達式的語法、特性及實際應用場景。什么是 Lambda 表達式&#xff1f;Lambda 表達…

Spring Boot注解詳解

文章目錄前言1. 核心啟動注解SpringBootApplicationEnableAutoConfigurationSpringBootConfiguration2. 組件注解Component及其衍生注解ComponentServiceRepositoryControllerRestController3. 依賴注入注解AutowiredQualifierPrimary4. Web相關注解請求映射注解RequestMapping…

Web開發:ABP框架12——中間件Middleware的創建和使用

一、簡介中間件可以用于鑒權、日志&#xff0c;攔截器可以用于指定方法或url的業務邏輯處理&#xff0c;兩者分工不同&#xff0c;實現效果相似&#xff0c;先執行中間件&#xff0c;后執行攔截器&#xff0c;再到WebAPI接口。二、示例一個Token驗證中間件三、代碼1.Startup.cs…