1. 程式人生 > >Linux核心模組模型面向物件分析

Linux核心模組模型面向物件分析

http://www.cnblogs.com/wenhuisun/archive/2013/02/22/2921781.html

Linux核心模組模型面向物件分析

CC++,它們的關係演變過程是怎樣的。從Linux的核心程式碼裡面你可以瞭解到更深的程式設計層次的面向物件,而不是簡單的封裝、繼承、多型。首先這個題目有點大,而且過於深,而我能瞭解到的也只是冰山一角,不過我覺得能去做這樣的一種有意義的工作,對於提升自己來說,也是很有幫助。

主要分以下幾部分:

  1. 引言。

  2. C語言中的封裝、繼承與多型。

  3. Linux體系裝置驅動模型(defs)來看面向物件。

  4. 類比外掛系統來看核心模組模型中層疊技術的可擴充套件性。

  5. 虛擬函式表與Linux核心符號匯出表的面向物件特性優劣分析。

  6. 總結

  7. 附錄

其中,每一部分都會穿插部分語言程式碼,讓整個描述過程更加詳實、不空洞。

引言:

Linux作業系統架構在合適的硬體之上,諸如 cpu、外存、記憶體、PCI等裝置之上。在Linux這個國家裡,任何的硬體裝置都作為一個資源,而作業系統就像一個國家機器對他的資源進行管理,國家的公民是執行與作業系統內部的程序,當然這個國家也有公務員(核心執行緒:注,在核心中沒有程序只有執行緒。關於什麼是執行緒什麼是程序,很多書上其實都描述的不在要點。詳見附錄問題1)。核心執行緒把持著所有的硬體資源,程序使用需要發起

80軟中斷(INT 0x80)請求核心響應。資源主要分為:記憶體/虛存、檔案(裝置)兩大類。

2 C語言中的封裝、繼承與多型:

封裝定義是在程式上,隱藏物件的屬性和實現細節,僅對外公開介面,控制在程式中屬性的讀和修改的訪問級別;將抽象得到的資料和行為(或功能)相結合,形成一個有機的整體,也就是將資料與操作資料的原始碼進行有機的結合,形成“類”,其中資料和函式都是類的成員。

假設我們有類A, 其內含有abc三個成員變數,並有操作方法 op_a(a)op_b(b)op_c(c)op_ab(a, b)等。在面嚮物件語言中及其容易實現,在C語言中面臨的最大問題是操作方法及其引數傳遞。

通過函式表可以彌補語言機制上的缺陷:

struct Ops {

void (*op_a) (struct A *, loff_t, int);

void (*op_b) (struct A *, char __user *, size_t, loff_t *);

void (*op_ab) (struct A *, const char __user *, size_t, loff_t *);

};

首先這是一個只含有方法的結構體,我們稱之為函式表,傳遞的結構體引數Ac++中預設編譯器為類傳遞的this物件,這樣,我們將結構體ops內嵌到結構體A中,如下:

Struct A{

Int a;

Int b;

Int c;

Struct Ops ops;

}

將方法封裝到了結構體中。在這裡結構體A相當於一個父類,而ops是作為父類公開給子類的介面。抽象出了介面,多型就很容易實現了。從這裡模擬封裝的過程,可以很容易發現介面的實質是父類提前為子類預留的佔位符,是一種“高瞻遠矚”的行為。

最早C++裡面的封裝是從C中的標頭檔案規則衍生出來的。其關鍵在於對於一個公共資料操作方法的歸類。如果一個公共變數,被很多個函式修改,如下圖:

 

後期除錯及維護時,帶來極大的不便,因為根本不知道系統中到底有多少函式操作的這塊資料,這塊資料的狀態什麼時候,被哪個函式改變了狀態。所以就演變成了下面的方式:

將操作此資料的函式放到同一個檔案中去,任何其它改變或訪問此資料的函式都需要通過這個檔案中的函式來訪問。

 

所以面向物件中的類,其實是C工程中總結出來的一系列管理方法在語言層面上的實現,並沒有太多的新東西。

多型:是允許將父物件設定成為和一個或更多的他的子物件相等的技術,賦值之後,父物件就可以根據當前賦值給它的子物件的特性以不同的方式運作。

由多型的定義,最關鍵的地方在於執行時切換即在編譯期不能確定需要執行的程式碼。這裡我們宣告兩個子操作表 ops1ops2,當需要使用ops2時,將 A->ops = ops2,即將子類例項化到父類,下面類A的具體操作就會採用ops2操作表中的方法。如圖:

 

程式碼示例:

Struct A a;

a-> ops = ops1;

a->ops->op_a(a);

//切換

a->ops = ops2;

a->ops->op_a(a);

繼承:特殊類(或子類、派生類)的物件擁有其一般類(或稱父類、基類)的全部屬性與服務,稱作特殊類對一般類的繼承。

繼承的本質是保留父類的一些成員和函式,實質上是保留父類的儲存區及跳轉函式表,繼承在C語言中也是採用內嵌結構體的方式來實現的。這裡舉核心中的連結串列結構體來說明,

我們通常所使用連結串列結構如下:

Struct A_LIST{

Int a;

Int b;

Struct A_LIST* next;

}

在這裡我們發現,每一個特定型別的連結串列機構都需要為其增加一個next或者prev欄位來保持連結串列的結構。還需要為每一個特定的連結串列類實現脫鏈、入鏈操作等。我們需要抽象出一個“基類”來實現連結串列的功能,其他連結串列類只需要簡單的繼承這個連結串列類就可以了。

Linux 核心的連結串列結構:

struct hst_head{

struct list_head *next, prey

)

在這個結構體中,連結串列及作為一個單獨的結構體,不再依附與任何物件。

同上面的例子,我們只需要宣告

Struct A_LIST{

Int a;

Int b;

Struct hst_head T* list;

}

這樣A_LIST即可作為一個連結串列物件,其連結串列操作均由其成員list代為實現,起到了繼承基類的可複用方法的作用。實際過程如下圖:

 

其作為一個連線件,只對本身結構體負責,而不需要關注真正歸屬的結構體。正如繼承的特性,父類的方法無法操作也不需要操作子類的成員。(關於從連線件獲取宿主結構體方法見附錄1.問題2

至此,C在面向物件的三大特性的實現過程就結束了。

Linux體系裝置驅動模型(defs)來看面向物件:

Sysfs:用於將系統中的裝置組織成層次結構,並向用戶模式程式提供詳細的核心資料結構。

Sysfs是一個特殊的檔案系統,沒有實際存放檔案的介質,sysfs資訊來源於kobject層次結構,讀取sys就是動態的從kobject結構鏈中提取資訊。

兩個基礎的資料結構kobjectkset

Kobject <linux/kobject.h>

struct kobject
{
        const char        * k_name; //
指向
kobject名稱的起始位置
        char                name[KOBJ_NAME_LEN];//
不足則重新分配(
20
        struct kref        kref; /*
引用計數
*/
        struct list_head    entry; /*
在所掛到連結串列的連線體
*/
        struct kobject          * parent; //
指向
kobject的父物件       

struct kset             * kset; /*指向所屬的kset*/
  struct kobj_type       * ktype; //
指向其物件型別描述符的指標

  struct dentry        * dentry;

//sysfs檔案系統中與該物件對應的檔案節點目錄項
};

引用計數的增加和減小;(操作kref

struct kobject *kobject_get(struct kobject *kobj);
void kobject_put(struct kobject *kobj);

如果引用計數降為0,呼叫kobject release() 釋放此結構

相關初始化工作

void kobject_init(struct kobject * kobj) kobject初始化函式。

Int kobject_set_name(struct kobject *kobj, const char *format, ...)kobject 名稱

int kobject_add(struct kobject * kobj) 加入linux裝置層次

void kobject_del(struct kobject * kobj) 從層次中刪除此物件

  1. 掛接該kobject物件到ksetlist

  2. 增加父目錄各級kobject的引用計數

  3. 在其parent指向的目錄下建立檔案節點

註冊與登出:

int kobject_register(struct kobject * kobj)

  1. kobject init()

  2. kobject_add()

void kobject_unregister(struct kobject * kobj)

  1. kobject_del()

  2. kobject_put() 如果引用計數降為0,呼叫kobject release() 釋放此結構

kobj_type的目標就是為不同型別的kobject提供不同的屬性以及銷燬方法。

Kobj type struct kobj_type {

void (*release)(struct kobject *); //kobject銷燬時呼叫的函式kobject_put()呼叫

struct sysfs_ops * sysfs_ops; //對屬性的操作表

struct attribute ** default_attrs; //屬性列表

};

操作表:
struct sysfs_ops {

    ssize_t    (*show)(struct kobject *, struct attribute *,char *);

    ssize_t    (*store)(struct kobject *,struct attribute *,const char *, size_t);

};

struct kset {

struct subsystem * subsys; 所在的subsystem的指標

struct kobj type * ktype; 指向該kset物件型別描述符的指標

struct list head list; 用於連線該kset中所有kobject的連結串列頭

struct kobject kobj; 嵌入的kobject

struct kset hotplug ops * hotplug ops; 指向熱插拔操作表的指標

};

Listkobject的雙向連結串列頭,ktype為物件型別供所有kobject共享。Kobj為所有kobject指向的parent域。Kset的引用計數依賴其成員kobj的引用計數

根據以上資料結構總結如下:

一共存在三條鏈:

1、子kobj雙向連結串列(有list做鏈頭)

2、 父子鏈(kobj

3、 歸屬鏈 (kset)

在面向物件中的正反向引用(111對多)在C中的實現過程如上:

當處理一對多的關係時,“一”需要維護一個“多”的連結串列,而“多”需要維護一個“一”的指標。

類比外掛系統來看核心模組模型中層疊技術的可擴充套件性。

這裡我們分析一個大名鼎鼎的外掛架構OSGI,包括eclipse在內的眾多外掛系統均是依照OSGI規範來架構自己的外掛系統的。

從面向物件的角度來說,構建外掛系統如同堆積木,又像企業架構匯流排ESB,其上的外掛可以做到熱插拔,而不影響整個系統的穩定。架構圖如下:

 

外掛配置檔案舉例:

下面的是外掛系統SharpDevelop中,關於Html幫助文件的一段外掛配置資訊:

<AddInname = "Help 2.0 Environment for SharpDevelop"

author = "Mathias Simmack"

description = "integrates Microsoft's Help 2.0 Environment"

addInManagerHidden = "preinstalled">

//對應外掛的描述資訊

<Manifest>

//核心資訊

<Identityname = "ICSharpCode.HtmlHelp2"/>

//標識自己的ID,供整個系統中訪問(防止重名,採用了名稱空間的命名方式)

<Dependencyaddin="SharpDevelop"/>

//依賴外掛

</Manifest>

<Runtime>

//執行期DLL匯入要求(載入此外掛時需要動態匯入的DLL連結庫)

<Importassembly="HtmlHelp2.dll"/>

</Runtime>

//外掛樹構造結點

<

相關推薦

Linux核心模組模型面向物件分析

http://www.cnblogs.com/wenhuisun/archive/2013/02/22/2921781.html Linux核心模組模型面向物件分析 C到C++,它們的關係演變過程是怎樣的。從Linux的核心程式碼裡面你可以瞭解到更深的

面向物件分析Linux核心裝置驅動(2)——Linux核心裝置模型與匯流排

Linux核心裝置模型與匯流排 -         核心版本 Linux Kernel 2.6.34, 與 Robert.Love的《Linux Kernel Development》(第三版)所講述的核心版本一樣 1.      Linux核心裝置模型分析 1)  

面向物件分析的三個模型和五個層次

在面向物件分析中,主要由物件模型、動態模型和功能模型組成。物件模型是最基本、最重要、最核心的。   用面向物件方法開發軟體,通常需要建立3種形式的模型,它們分別是描述系統資料結構的物件模型,描述系統控制結構的動態模型和描述系統功能的功能模型。一個典型的軟體系統使用資料結構(物件模型),執行操作(

.NET應用架構設計—面向物件分析與設計四色原型模式(彩色建模、領域無關模型)(概念版)

閱讀目錄: 1.背景介紹 2.問自己,UML對你來說有意義嗎?它幫助過你對系統進行分析、建模嗎? 3.一直以來其實我們被一個縫隙隔開了,使我們對OOAD遙不可及 4.四色原型模式填補這個歷史縫隙,讓我們真的看見OOAD的希望 5.在四色原型上運用彩色建模增強視覺衝擊力 6.通過四色原

LINUX核心模組載入Windows下驅動

最近一段時間以來,幾乎每一臺行動式計算機都內建了無線功能,但是它們中有很多並不支援Linux。因此,除非這些計算機設定了雙啟動,這樣做LINUX使用者也未必可以使用無線網絡卡,儘管如此,除非Windows正在執行,否則這些便攜計算機可能依然無法連線到無線網路。   最近一段時間以來,幾乎每一臺行

Linux核心模組程式設計

Linux核心模組程式設計 (作者:Baron_wu 禁止轉載) 首先,建立一個核心模組並插入Linux核心中。這是實驗第一部分 首先檢視當前核心模組使用情概況:lsmod Module:模組名 Size:模組大小 Used by:這些模組在哪被使用 接下來編寫一個simple.c

linux 核心模組程式設計之LED驅動程式(六)

我使用的是tiny6410的核心板,板子如下,淘寶可以買到 為了不與板子上的任何驅動發生IO衝突,我使用CON1那一排沒用到的IO口,引腳如下   LED1 LED2 LED3 LED4

linux 核心模組程式設計之核心符號匯出(五)

/proc/kallsyms 記錄了核心中所有匯出的符號的名字與地址 我們需要編譯2個核心模組,然後其中一個核心模組去呼叫另一個核心模組中的函式 hello.c程式碼如下 #include <linux/module.h> #include <linux/in

linux 核心模組程式設計之模組引數(四)

通過巨集module_param指定模組引數,模組引數用於在載入模組時傳遞給模組。 module_param(name, type, perm) name是模組引數的名字 type是這個引數的型別,常見值:bool、int、charp(字串型) perm是模組

linux 核心模組程式設計之編譯多個原始檔(三)

編譯擁有多個原始檔的核心模組的方式和編譯一個原始檔的方式差不多,我們先來看下我們需要的檔案都有哪些。 首先是main.c檔案 #include <linux/module.h> #include <linux/init.h> MODULE_LICENSE

linux 核心模組程式設計之hello word(二)

我們的目的是要編譯個hello.ko的檔案,然後安裝到核心中。 先來看下需要的程式碼,hello.c檔案如下 #include <linux/module.h> #include <linux/init.h> static int hello_init(vo

linux 核心模組程式設計之環境搭建(一)

這裡介紹些關於Tiny6410開發板核心的編譯,為後期驅動開發做前期的準備。 開發環境:64位的Ubuntu 14.01虛擬機器 目標機:友善之臂Tiny6410開發板 核心:linux-2.6.38-20110325.tar.gz 核心原始碼下載地址 htt

《超市管理系統的面向物件分析》論文筆記

一、基本資訊 標題:超市管理系統的面向物件分析 時間:2016 來源:科技展望 關鍵詞:超市管理系統; 用例圖; 面向物件; 二、研究內容 1.主要內容:         基於中小型超市的特點:規模較小,庫存量不大。用面向物件的方法對超

Linux核心模組程式設計——Hello World

一、實驗環境: 環境配置:VMware® Workstation 15 Pro、ubuntu Desktop 18.10、記憶體 2GB、處理器數量2、每個處理器核心數量1、硬碟大小30GB……還有一個就是用的咱Xidian的源(因為校內不需要流量啊,而且還很快!) 二、知識儲備

Linux核心模組程式設計系列1

1.準備工作 使用如下命令檢視自己Linux的核心版本 uname -a 結果如下: Linux VM-73-203-debian 4.9.0-6-amd64 #1 SMP Debian 4.9.88-1+deb9u1 (2018-05-07) x86_64 GNU/Lin

JAVA中OOAD(面向物件分析與設計依賴倒置原則)程式碼例項

簡介:什麼是依賴倒置原則? 軟體設計中,多層次之間相互依賴關係需要倒置為抽象類或介面,而不是直接依賴於具體的實現。 具體表現為: 1、上層模組不應該直接依賴下層實現,而應該依賴下層的抽象 2、每一個單獨的層次,抽象不應該依賴於細節,而細節應該依賴於抽象。 現在有一個使用者類UserBea

軟體工程小記——面向物件分析

第八章 面向物件分析 1.傳統軟體工程方法對應的軟體過程模型(或者軟體生命週期模型)通常是瀑布模型,劃分為以下階段:     a.問題定義;     b.需求分析;     c.可行性研究;  &

Linux核心模組開發 Slab快取記憶體介面與用例

在核心模組開發或者驅動開發中經常會使用到記憶體分配,常見的方式是呼叫 kmalloc 介面分配記憶體。 static __always_inline void *kmalloc(size_t size, gfp_t flags); kmalloc介面使用簡單,並且不會對所

軟體設計工程——面向物件分析與設計

面向物件技術 面向物件=物件+分類+繼承+通過訊息的通訊 設計流程: 1.物件分析(OOA); 2.物件設計(OOD); 3.面向物件程式設計(OOP); 4.畫UML圖 5.加入設計模式 面向物件分析(OOA) 1.認定物件:實質性物件; 2.組織物件:分析物件

js裡的面向物件分析-(建立例項化物件) 建構函式

ECMAScript 有兩種開發模式:1.函式式(過程化),2.面向物件(OOP)。面向物件的語言有一個標誌,那就是類的概念,而通過類可以建立任意多個具有相同屬性和方法的物件。但是,ECMAScript 沒有類的概念,因此它的物件也與基於類的語言中的物件有所不同。 js本身