<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      《Linux內(nèi)核設(shè)計(jì)與實(shí)現(xiàn)》讀書筆記(十九)- 可移植性

      linux內(nèi)核的移植性非常好, 目前的內(nèi)核也支持非常多的體系結(jié)構(gòu)(有20多個(gè)).

      但是剛開始時(shí), linux也只支持 intel i386 架構(gòu), 從 v1.2版開始支持 Digital Alpha, Intel x86, MIPS和SPARC(雖然支持的還不是很完善).

      從 v2.0版本開始加入了對(duì) Motorala 68K和PowerPC的官方支持, v2.2版本開始新增了 ARMS, IBM S390和UltraSPARC的支持.

      v2.4版本支持的體系結(jié)構(gòu)數(shù)達(dá)到了15個(gè), v2.6版本支持的體系結(jié)構(gòu)數(shù)目提高到了21個(gè).

      目前的我使用的系統(tǒng)是 Fedora20, 支持的體系結(jié)構(gòu)有31個(gè)之多.(源碼樹中 arch目錄下有支持的體系結(jié)構(gòu), 每種體系結(jié)構(gòu)一個(gè)文件夾)

       

      考慮到內(nèi)核支持如此之多的架構(gòu), 在內(nèi)核開發(fā)的時(shí)候就需要考慮編碼的可移植性.

      提高可移植性最重要的就是要搞明白不同體系結(jié)構(gòu)之間究竟是什么對(duì)移植代碼的影響比較大.

      主要內(nèi)容:

      • 字長
      • 數(shù)據(jù)類型
      • 數(shù)據(jù)對(duì)齊
      • 字節(jié)順序
      • 時(shí)間
      • 頁長度
      • 處理器順序
      • SMP, 內(nèi)核搶占, 高端內(nèi)存
      • 總結(jié)

       

      1. 字長

      這里的字是指處理器能夠一次完成處理的數(shù)據(jù). 字長即使處理器能夠一次完成處理的數(shù)據(jù)的最大長度.

      目前的處理器主要有32位和64為2種, 注意這里的32位和64位并不是指操作系統(tǒng)的版本, 而是指處理器的能力.

      一般來說, 32位的處理器只能安裝32位的操作系統(tǒng), 而64位的處理器可以安裝32位的操作系統(tǒng), 也可以安裝64位的操作系統(tǒng).

       

      對(duì)于一種體系結(jié)構(gòu)來說, 處理器通用寄存器(general-purpose registers, GPR)的大小和它的字長是相同的.

      C語言定義的long類型總是對(duì)等于機(jī)器的字長, 而int型有時(shí)會(huì)比字長小.

      • 32位的體系結(jié)構(gòu)中, int型和long型都是32位的
      • 64位的體系結(jié)構(gòu)中, int型是32位的, long型是64位的.

       

      內(nèi)核編碼中涉及到字長的部分時(shí), 牢記以下準(zhǔn)則:

      1. ANSI C標(biāo)準(zhǔn)規(guī)定, 一個(gè)char的長度一定是一個(gè)字節(jié)(8位)
      2. linux當(dāng)前所支持的體系結(jié)構(gòu)中, int型都是32位的
      3. linux當(dāng)前所支持的體系結(jié)構(gòu)中, short型都是16位的
      4. linux當(dāng)前所支持的體系結(jié)構(gòu)中, 指針和long型的長度不定, 在32位和64位中變化
      5. 不能假設(shè) sizeof(int) == sizeof(long)
      6. 類似的, 不能假定 指針的長度和int型相同.

       

      此外, 操作系統(tǒng)有個(gè)簡單的助記符來描述此系統(tǒng)中數(shù)據(jù)類型的大小.

      • LLP64 :: 64位的Windows, long類型和指針都是64位
      • LP64 :: 64位的Linux, long類型和指針都是64位
      • ILP32 :: 32位的Linux, int類型, long類型和指針都是32位
      • ILP64 :: int類型, long類型和指針都是64位(非Linux)

       

      2. 數(shù)據(jù)類型

      編寫可移植性代碼時(shí), 內(nèi)核中的數(shù)據(jù)類型有以下3點(diǎn)需要注意:

       

      2.1 不透明類型

      linux內(nèi)核中定義了很多不透明類型, 它們是在C語言標(biāo)準(zhǔn)類型上的一個(gè)封裝, 比如 pid_t, uid_t, gid_t 等等.

      例如, pid_t的定義可以在源碼中找到:

      typedef __kernel_pid_t        pid_t;  /* include/linux/types.h */
      
      typedef int        __kernel_pid_t;    /* arch/asm/include/asm/posix_types.h */

       

      使用這些不透明類型時(shí), 以下原則需要注意:

      1. 不要假設(shè)該類型的長度(那怕通過源碼看到了它的C語言類型), 這些類型在不同體系結(jié)構(gòu)中可能長度會(huì)變, 內(nèi)核開發(fā)者也有可能修改它們
      2. 不要將這些不透明類型轉(zhuǎn)換為C標(biāo)準(zhǔn)類型來使用
      3. 編程時(shí)保證不透明類型實(shí)際存儲(chǔ)空間或者格式發(fā)生變化時(shí)代碼不受影響

       

      2.2 長度確定的類型

      除了不透明類型, linux內(nèi)核中還定義了一系列長度明確的數(shù)據(jù)類型, 參見 include/asm-generic/int-l64.h 或者 include/asm-generic/int-ll64.h

      typedef signed char s8;
      typedef unsigned char u8;
      
      typedef signed short s16;
      typedef unsigned short u16;
      
      typedef signed int s32;
      typedef unsigned int u32;
      
      typedef signed long s64;
      typedef unsigned long u64;

       

      上面這些類型只能在內(nèi)核空間使用, 用戶空間無法使用. 用戶空間有對(duì)應(yīng)的變量類型, 名稱前多了2個(gè)下劃線:

      typedef __signed__ char __s8;
      typedef unsigned char __u8;
      
      typedef __signed__ short __s16;
      typedef unsigned short __u16;
      
      typedef __signed__ int __s32;
      typedef unsigned int __u32;
      
      typedef __signed__ long __s64;
      typedef unsigned long __u64;

       

      2.3 char類型

      之所以把char類型單獨(dú)拿出來說明, 是因?yàn)閏har類型在不同的體系結(jié)構(gòu)中, 有時(shí)默認(rèn)是帶符號(hào)的, 有時(shí)是不帶符號(hào)的.

      比如, 最簡單的例子:

      /*
       * 某些體系結(jié)構(gòu)中, char類型默認(rèn)是帶符號(hào)的, 那么下面 i 的值就為 -1
       * 某些體系結(jié)構(gòu)中, char類型默認(rèn)是不帶符號(hào)的, 那么下面 i 的值就為 255, 與預(yù)期可能有差別!!!
       */
      char i = -1;

       

      避免上述問題的方法就是, 給char類型賦值時(shí), 明確是否帶符號(hào), 如下:

      signed char i = -1;  /* 明確 signed, i 的值在哪種體系結(jié)構(gòu)中都是 -1 */
      unsigned char i = 255;  /* 明確 unsigned, i 的值在哪種體系結(jié)構(gòu)中都是 255 */

       

      3. 數(shù)據(jù)對(duì)齊

      數(shù)據(jù)對(duì)齊也是增強(qiáng)可移植性的一個(gè)重要方面(有的體系結(jié)構(gòu)對(duì)數(shù)據(jù)對(duì)齊要求非常嚴(yán)格, 載入未對(duì)齊的數(shù)據(jù)可導(dǎo)致性能下降, 甚至錯(cuò)誤).

      數(shù)據(jù)對(duì)齊的意思就是: 數(shù)據(jù)的內(nèi)存地址可以被 4 整除

       

      1. 通過指針轉(zhuǎn)換類型時(shí), 不要轉(zhuǎn)換長度不一樣的類型, 比如下面的代碼有可能出錯(cuò)

      /*
       * 下面的代碼將一個(gè)變量從 char 類型轉(zhuǎn)換為 unsigned long 類型, 
       * char 類型只占 1個(gè)字節(jié), 它的地址不一定能被4整除, 轉(zhuǎn)換為 4個(gè)字節(jié)或者8個(gè)字節(jié)的 usigned long之后,
       * 導(dǎo)致 unsigned long 出現(xiàn)數(shù)據(jù)不對(duì)齊的現(xiàn)象.
       */
      char wolf[] = "Like a wolf";
      char *p = &wolf[1];
      unsigned long p1 = *(unsigned long*) p;

       

      2. 對(duì)于數(shù)組, 安裝基本數(shù)據(jù)類型進(jìn)行對(duì)齊就行.(數(shù)組元素的存放在內(nèi)存中是連續(xù)的, 第一個(gè)對(duì)齊了, 后面的都自動(dòng)對(duì)齊了)

      3. 對(duì)于聯(lián)合體, 長度最大的數(shù)據(jù)對(duì)齊就可以了

      4. 對(duì)于結(jié)構(gòu)體, 保證結(jié)構(gòu)體中每個(gè)元素能夠正確對(duì)齊即可

      如果結(jié)構(gòu)體中的元素沒有對(duì)齊, 編譯器會(huì)自動(dòng)填充結(jié)構(gòu)體, 保證它是對(duì)齊的. 比如下面的代碼, 預(yù)計(jì)應(yīng)該輸出12, 實(shí)際卻輸出了24

      我的代碼運(yùn)行環(huán)境: Fedora20 x86_64

      /******************************************************************************
       * @file    : struct_align.c
       * @author  : wangyubin
       * @date    : 2014-01-09
       * 
       * @brief   : 
       * history  : init
       ******************************************************************************/
      
      #include <stdio.h>
      
      struct animal_struct
      {
          char dog;                   /* 1個(gè)字節(jié) */
          unsigned long cat;          /* 8個(gè)字節(jié) */
          unsigned short pig;         /* 2個(gè)字節(jié) */
          char fox;                   /* 1個(gè)字節(jié) */
      };
      
      int main(int argc, char *argv[])
      {
          /* 在我的64bit 系統(tǒng)中是按8位對(duì)齊, 下面的代碼輸出 24 */
          printf ("sizeof(animal_struct)=%d\n", sizeof(struct animal_struct));
          return 0;
      }

      測試方法:

      gcc -o test struct_align.c
      ./test   # 輸出24

       

      結(jié)構(gòu)體應(yīng)該被填充成如下形式:

      struct animal_struct
      {
          char dog;                   /* 1個(gè)字節(jié) */
          /* 此處填充了7個(gè)字節(jié) */
          unsigned long cat;          /* 8個(gè)字節(jié) */
          unsigned short pig;         /* 2個(gè)字節(jié) */
          char fox;                   /* 1個(gè)字節(jié) */
          /* 此處填充了5個(gè)字節(jié) */   
      };

       

      通過調(diào)整結(jié)構(gòu)體中元素順序, 可以減少填充的字節(jié)數(shù), 比如上述結(jié)構(gòu)體如果定義成如下順序:

      struct animal_struct
      {
          unsigned long cat;          /* 8個(gè)字節(jié) */
          unsigned short pig;         /* 2個(gè)字節(jié) */
          char dog;                   /* 1個(gè)字節(jié) */
          char fox;                   /* 1個(gè)字節(jié) */
      };

      那么為了保證8位對(duì)齊, 只需在后面補(bǔ)充 4位即可:

      struct animal_struct
      {
          unsigned long cat;          /* 8個(gè)字節(jié) */
          unsigned short pig;         /* 2個(gè)字節(jié) */
          char dog;                   /* 1個(gè)字節(jié) */
          char fox;                   /* 1個(gè)字節(jié) */
          /* 此處填充了4個(gè)字節(jié) */   
      };

       

      調(diào)整后的代碼會(huì)輸出 16, 不是之前的24

      #include <stdio.h>
      
      struct animal_struct
      {
          unsigned long cat;          /* 8個(gè)字節(jié) */
          unsigned short pig;         /* 2個(gè)字節(jié) */
          char dog;                   /* 1個(gè)字節(jié) */
          char fox;                   /* 1個(gè)字節(jié) */
      };
      
      int main(int argc, char *argv[])
      {
          /* 在我的64bit 系統(tǒng)中是按8位對(duì)齊, 下面的代碼輸出 16 */
          printf ("sizeof(animal_struct)=%d\n", sizeof(struct animal_struct));
          return 0;
      }

      測試方法:

      gcc -o test struct_align.c
      ./test  # 輸出16

       

      注意: 雖然調(diào)整結(jié)構(gòu)體中元素的順序可以減少填充的字節(jié), 從而降低內(nèi)存的消耗.

      但是對(duì)于內(nèi)核中已有的那些結(jié)構(gòu), 千萬不能隨便調(diào)整其元素順序, 因?yàn)閮?nèi)核中很多現(xiàn)存的方法都是通過元素在結(jié)構(gòu)體中位置偏移來獲取元素的.

       

      4. 字節(jié)順序

      字節(jié)順序其實(shí)只有2種:

      • 低位優(yōu)先 :: little-endian 數(shù)據(jù)由低位地址->高位地址存放
      • 高位優(yōu)先 :: big-endian 數(shù)據(jù)由高位地址->低位地址存放

       

      比如占有四個(gè)字節(jié)的整數(shù)的二進(jìn)制表示如下:

      00000001 00000002 00000003 00000004

       

      內(nèi)存地址方向:   高位  <--------------------> 低位

      little-endian 表示如下: 

      00000001 00000002 00000003 00000004

      big-endian 表示如下:

      00000004 00000003 00000002 00000001

       

      判斷一個(gè)體系結(jié)構(gòu)是 big-endian 還是 little-endian 非常簡單.

      int x = 1;  /* 二進(jìn)制 00000000 00000000 00000000 00000001 */
      
      /* 
       * 內(nèi)存地址方向:   高位  <--------------------> 低位
       * little-endian 表示: 00000000 00000000 00000000 00000001
       * big-endian 表示:    00000001 00000000 00000000 00000000
       */
      if (*(char *) &x == 1)   /* 這句話把int型轉(zhuǎn)為char型, 相當(dāng)于只取了int型的最低8bit */
          /* little-endian */
      else
          /* big-endian */

       

      5. 時(shí)間

      內(nèi)核中使用到時(shí)間相關(guān)概念時(shí), 為了提高可移植性, 不要使用時(shí)間中斷的發(fā)生頻率(也就是每秒產(chǎn)生的jiffies), 而應(yīng)該使用 HZ 來正確使用時(shí)間.

      關(guān)于 jiffies 和 HZ 的概念, 可以參考之前的博客: 《Linux內(nèi)核設(shè)計(jì)與實(shí)現(xiàn)》讀書筆記(十一)- 定時(shí)器和時(shí)間管理

       

      6. 頁長度

      當(dāng)處理用頁管理的內(nèi)存時(shí), 不要既定頁的長度為 4KB, 在不同的體系結(jié)構(gòu)中長度會(huì)不一樣.

      而應(yīng)該使用 PAGE_SIZE 以字節(jié)數(shù)來表示頁長度, 使用 PAGE_SHIFT 表示從最右端屏蔽了多少位能夠得到該地址對(duì)應(yīng)的頁的頁號(hào).

      PAGE_SIZEPAGE_SHIFT 都是宏, 定義在 include/asm-generic/page.h

       

      下表是一些體系結(jié)構(gòu)中頁長度:

      體系結(jié)構(gòu)

      PAGE_SHIFT

      PAGE_SIZE

      alpha 13 8KB
      arm 12, 14, 15 4KB, 16KB, 32KB
      avr 12 4KB
      cris 13 8KB
      blackfin 12 16KB
      h8300 14 4KB
        12 4KB, 8KB, 16KB, 32KB
      m32r 12, 13, 14, 16 4KB
      m68k 12 4KB, 8KB
      m68knommu 12, 13 4KB
      mips 12 4KB
      min10300 12 4KB
      parisc 12 4KB
      powerpc 12 4KB
      s390 12 4KB
      sh 12 4KB
      sparc 12, 13 4KB, 8KB
      um 12 4KB
      x86 12 4KB
      xtensa 12 4KB

       

      7. 處理器順序

      還有最后一個(gè)和可移植性相關(guān)的注意點(diǎn)就是處理器對(duì)代碼的執(zhí)行順序, 在有些體系結(jié)構(gòu)中, 處理器并不是嚴(yán)格按照代碼編寫的順序執(zhí)行的,

      可能為了優(yōu)化性能或者其他原因, 處理器執(zhí)行指令的順序與編寫的代碼的順序稍有出入.

       

      如果我們的某段代碼需要嚴(yán)格的執(zhí)行順序, 需要在代碼中使用 rmb() wmb() 等內(nèi)存屏障來確保處理器的執(zhí)行順序.

      關(guān)于rmb和wmb可以參考之前的博客: 《Linux內(nèi)核設(shè)計(jì)與實(shí)現(xiàn)》讀書筆記(十)- 內(nèi)核同步方法  第 11 小節(jié)

       

      8. SMP, 內(nèi)核搶占, 高端內(nèi)存

      SMP, 內(nèi)核搶占和高端內(nèi)存本身雖然和可移植性沒有太大的關(guān)系, 但它們都是內(nèi)核中重要的配置選項(xiàng),

      如果編碼時(shí)能夠考慮到這些的話, 那么即使內(nèi)核修改SMP等這些配置選項(xiàng), 我們的代碼仍然可以安全可靠的運(yùn)行.

      所以, 在編寫內(nèi)核代碼時(shí)最好加上如下假設(shè):

      • 假設(shè)代碼會(huì)在SMP系統(tǒng)上運(yùn)行, 要正確選擇和使用鎖
      • 假設(shè)代碼會(huì)在支持內(nèi)核搶占的情況下運(yùn)行, 要正確使用鎖和內(nèi)核搶占語句
      • 假設(shè)代碼會(huì)運(yùn)行在使用高端內(nèi)存(非永久映射內(nèi)存)的系統(tǒng)上, 必要時(shí)使用 kmap()

       

      9. 總結(jié)

      編寫簡潔, 可移植性的代碼還需要通過實(shí)踐來積累經(jīng)驗(yàn), 上面的準(zhǔn)則可以作為代碼是否滿足可移植性的一些檢測條件.

      書中還提到的2點(diǎn)注意事項(xiàng), 我覺得不僅是編寫內(nèi)核代碼, 編寫任何代碼時(shí), 都應(yīng)該注意:

      • 編碼盡量選取最大公因子 :: 假定任何事情都有可能發(fā)生, 任何潛在的約束也都存在
      • 編碼盡量選取最小公約數(shù) :: 不要假定給定的內(nèi)核特性是可用的, 僅僅需要最小的體系結(jié)構(gòu)功能

       

      雖然編寫可移植性代碼需要遵守這么多的原則, 但是不能畏懼, 在學(xué)習(xí)內(nèi)核開發(fā)的過程中, 只有不斷的嘗試, 不斷的犯錯(cuò), 才能確實(shí)的掌握內(nèi)核.

      posted @ 2014-01-09 13:49  wang_yb  閱讀(3745)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 国产亚洲精品福利在线无卡一| 三级三级三级A级全黄| 国产妇女馒头高清泬20p多毛| 国产成人一区二区三区免费| 国产蜜臀在线一区二区三区| 在线人成免费视频69国产| 少妇人妻偷人精品免费| 久久热99这里只有精品| 在线日韩一区二区| 韩国精品一区二区三区在线观看| 九九热视频精品在线播放| 亚洲av日韩av永久无码电影| 久热久热中文字幕综合激情| 日本欧美大码a在线观看| 久久亚洲欧美日本精品| 天美麻花果冻视频大全英文版| 欧美福利在线| 精品国产一区二区在线视| 91精品亚洲一区二区三区| 福利一区二区不卡国产| 国产美女深夜福利在线一| 国产在线欧美日韩精品一区| 久人人爽人人爽人人片av| 久久久av男人的天堂| 嫩b人妻精品一区二区三区| 国产一区二区四区不卡| 中文字幕人妻无码一区二区三区 | 免费看视频的网站| 亚洲AV日韩AV激情亚洲| 亚洲色婷婷综合开心网| 久久久久久久久久久久中文字幕 | 暖暖视频日本在线观看| 中文字幕久久六月色综合| 天天澡日日澡狠狠欧美老妇| 国产不卡免费一区二区| 99RE8这里有精品热视频| 国产永久免费高清在线观看| 国产人妻熟女呻吟在线观看| 国产精品一区二区久久岳| 亚洲色最新高清AV网站| 人妻精品动漫H无码中字|