嵌入式實時Hypervisor:XtratuM (9)

1.1           域間通信工具

爲了提高域之間的作業協作能力,域間通信(Inter-Domains Communication)工具被引入到XtratuM Hypervisor系統中。當前,XtratuM系統中存在兩種數據通信工具,一種是針對數據流的命名管道(FIFO),另外一種是針對塊數據的共享內存。命名管道是一種簡單的流數據傳輸工具,採用先進先出的策略,不同於PIPE(管道),命名管道有固定的存儲介質和名稱,它可以被任何域通過名稱打開和關閉。而管道只有存儲介質,沒有名稱。管道的存在依附於創建管道的任務,當任務退出時,管道也就相應的被銷燬了。而命名管道一經創建將會永久存在,知道用戶明顯的將其刪除[37]

共享內存是不同於命名管道的數據通信模式,用戶可以像打開普通文件一樣打開共享內存,並且可以指定共享內存大小。與命名管道相比,共享內存是塊設備,即任務可以隨機的訪問共享內存區間的任何地址的數據,並且不會因爲地址的不同而使訪問時間有所差別。但是FIFO類似的流數據通信工具,數據的傳輸和訪問必須有一個先後順序。因此,命名管道與共享內存雖然目的相同,但是在使用時一定要正確評估應用場景。

1.1.1              命名管道

基於XtratuM系統,FIFO/XM V1.0V2.0V3.0已經先後被髮布。其中V1.0採用了阻塞性同步競爭條件和系統調用的方法實現,在後續的版本中,V2.0V3.0就分別針對這兩種技術的缺陷,通過Lock-Free機制和內存映射機制解決相應問題。本節將詳細介紹三個版本的FIFO實現過程以及Lock-Free機制[38]

1.1.1.1            FIFO/XM V1.0

FIFO/XM主要包含共享FIFOLinux FIFO設備驅動和PaRTiKle FIFO設備驅動。共享FIFOV1.0中是被集成到XtratuM模塊裏面的。並且FIFO的訪問是非阻塞型,即當FIFO沒有數據時,如果任務試圖從裏面讀取數據時,任務會直接返回。當FIFO被寫滿後,繼續執行寫操作的任務也會直接返回。FIFO可以是雙向操作,即任何域可以對同一個FIFO進行讀或者寫操作。圖2-10給出了FIFO/XM V 1.0的架構模型。

圖2-1.          FIFO/XM V1.0架構模型

從圖2-10中可以清晰的看到LinuxPaRTiKle使用不同的FIFO設備驅動。Linux和普通的域通過不同的接口訪問底層的共享FIFO。在FIFO/XM的開發和測試環境中,PaRTiKle是普通的任務域。

XtratuM模塊被加載的時候,FIFO內存被靜態分配並且被鎖在物理內存中,這樣可以防止FIFO內存空間的換入或換出。默認情況下,16個大小爲PAGE SIZEFIFO被建立。Linux系統中FIFO設備驅動通過兩個導出全局函數鏈接訪問FIFO數據。但是,不同於Linux系統任務,PaRTiKle通過XtratuMHypercall層提供的兩個HypercallsFIFO進行訪問,xm_fifo_read() xm_fifo_write()。當PaRTiKle要訪問底層的FIFO設備時,PaRTiKle首先要調用xm_fifo_read()函數,該函數會執行int 0x82指令,從而觸發Hypercall異常,系統由PaRTiKle空間陷入XtratuM內核空間,然後調用xm_fifo_read_sys()函數對FIFO進行讀操作。熟悉Linux系統調度的讀者很容易明確這一部分的執行過程。PaRTiKle系統中的用戶態線程和Linux用戶態進程都通過POSIX APIsFIFO設備進行訪問和操作,例如open()close()read()write()等。在LinuxPaRTiKle系統中,FIFO設備的名稱爲/dev/rtf0,,/dev/rtf15,並且設備的最大號與最小號遵循Linux系統對命名管道的規定。圖2-11和圖2-12分別給出了FIFO/XMLinux系統和PaRTiKle系統中讀操作的函數調用樹。

圖2-11.       LinuxFIFO/XM設備函數調用樹

圖2-12.       PaRTiKleFIFO/XM設備函數調用樹

從圖2-11和圖2-12中可以看到底層從FIFO中讀數據函數都是xmf_read(),這也意味着在xmf_read()函數中會出現資源競爭訪問,包含實時域和非實時域之間的競爭。因此,爲了提高競爭資源的安全性,同步機制被引入到該函數中。在當前XtratuM版本中,除了屏蔽中斷,系統沒有提供其它的競爭條件方法。爲此,新的機制應該被引入到域間資源的競爭中。下面給出了xm_read()函數的算法。

int xmf_read(int index, char *dst, int size)

BEGIN

...

hw_save_flags_and_cli(&flags);

read_data();

hw_restore_flags(flags);

...

END

競爭條件並不僅僅存在於域之間對FIFO/XM的訪問中,並且存在於域內任務對設備的訪問。在LinuxPaRTiKle系統中,爲了避免內部的進程和線程對FIFO設備的競爭,它們採用了不同的函數避免競爭條件。在Linux系統中,FIFO/XM採用讀信號量和寫信號量對FIFO設備的訪問。而PaRTiKle中,由於提供的信號量功能相對比較少,讀寫FIFO設備將會採用同一種信號量。下面分別給出了LinuxPaRTiKle針對FIFO設備競爭條件的同步算法。

int linf_read(int fd, char *dest, int size)

BEGIN

...

down_read(&fifo.rw_semphore);

read_data();

up_read(&fifo_rw_semphore);

...

END

 

int linf_write(int fd, const char *src, int size)

BEGIN

...

down_write(&fifo.rw_semphore);

write_data();

up_wirte (&fifo_rw_semphore);

...

END

 

int prtkf_read(int fd, char *dest, int size)

BEGIN

...

sem_wait_sys (&fifo.rw_semphore);

read_data();

sem_post_sys(&fifo_rw_semphore);

...

END

上面的內容已經簡單的介紹了FIFO/XM V1.0的實現,希望讀者對FIFO設備能夠理解。但是,在FIFO/XM V1.0中存在一些缺陷。

l        中斷屏蔽機制可以解決多個域對FIFO資源的競爭條件。但是,其餘的任務甚至是中斷服務程序都無法得到執行。從而很大的影響了系統的實時行爲,尤其是當具有低優先級的域首先獲取資源時。尤其是在多核系統上,這種策略具有嚴重缺陷。

l        採用信號量機制解決競爭條件。信號量是一種基於阻塞的機制,並且會引起優先級倒置。並且,信號量的獲取和釋放會影響系統的性能。因此,新的同步機制需要創建和應用。

l        Linux系統和PaRTiKle系統中,對FIFO數據的訪問採用的系統調用或Hypercall,提高了系統延遲。

l        缺乏FIFO控制能力。在FIFO/XM 1.0中,僅僅提供了對FIFO讀和寫這兩種操作。沒有相應的控制功能和狀態檢查功能。

鑑於FIFO/XM 1.0存在的多種缺陷,進一步提高FIFO設備的效率和穩定性,在FIFO/XM V2.0FIFO/XM V3.0中引入了新的方法和技術。

1.1.1.2            Lock-Free機制

當前,有多種傳統的方式在同步領域得到實現和應用,例如spin-lock,信號量,BKL等。但是這些機制都是等待阻塞型機制,並且會引起優先級倒置問題。因此,Lock-Free機制應該被引入到FIFO設備訪問過程中。Lock-Free機制可以避免由傳統基於阻塞的條件競爭解決方案帶來的一些問題[39]

l        優先級倒置:當高優先級任務請求被低優先級任務持有的鎖時發生[40]

l        死鎖問題:不同的任務依照不同的序列試圖獲取同一個資源集中資源鎖時發生;

l        搶佔容忍:如果持鎖去睡眠,但是另外一個進程要去獲取該鎖。從而導致新任務去等待睡眠者,也就意味着新任務在無用的運行。

Lock-Free機制的目標是在不阻塞其它任務的前提下可以安全的訪問競爭資源,並且要保證資源操作的一致性。爲了實現Lock-Free機制,通常採用的基本方法是CAS(Compare-and-Swap)操作。CAS是嚴重依賴底層計算機平臺的一個原子操作。x86平臺採用cmpxchg指令實現CAS操作,該指令出現於X486等後繼的X86平臺中。下面列出了兩端代碼,一段是用C語言實現的CAS操作算法,另外一段是基於X86平臺實現的CAS操作[41]

int cas(int *addr, int old_value, int new_value)

{

if(*addr == old_value) {

*addr = new_value;

return 1;

}

return 0;

}

#define CAS(adr, ov, nv) ({ /

__typeof__(ov) ret; /

__asm__ __volatile__( /

"cmpxchg %3, %1" /

:"=a"(ret),

"+m"(*(volatile unsigned int *)(adr)) /

:"a"(ov),"r"(nv)); /

ret == ov; /

})

PowerPC平臺上,由於缺乏cmpxchg指令,爲了實現CAS功能,系統採用了Fetch-Store指令,下面是基於PowerPC 405 的僞cmpxchg() 指令代碼段。

static __inline__ unsigned long

cmpxchg(volatile int *p, int old, int new)

{

    int prev;

    __asm__ __volatile__ ("/n/

1:  lwarx  %0,0,%2 /n/

    cmpw   0,%0,%3 /n/

    bne 2f /n"

    PPC405_ERR77(0,%2)

"   stwcx. %4,0,%2 /n/

    bne-   1b/n"

"2:"

    : "=&r" (prev), "=m" (*p)

    : "r" (p), "r" (old), "r" (new), "m" (*p)

    : "cc", "memory");

    return prev;

}

上面簡單的介紹了Lock-Free機制和CAS操作在x86PowerPC平臺的實現,Lock-Free機制在FIFO/XM中的使用和實現將會在下面的部分介紹。

 

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