1. 程式人生 > >《Linux Device Drivers》第十一章 核心的資料型別——note

《Linux Device Drivers》第十一章 核心的資料型別——note

  • 簡介
    • 由於Linux的多平臺特性,任何一個重要的驅動程式都應該是可移植的
    • 與核心程式碼相關的核心問題是應該能夠同時訪問已知長度的資料項,並充分利用不同處理器的能力
    • 核心使用的資料型別主要被分成三類
      • 類似int這樣的標準C語言型別
      • 類似u32這樣的有確定大小的型別
      • 像pid_t這樣的用於特定核心物件的型別
    • 本章將討論在什麼情況下使用這三種類型以及如何使用
  • 使用標準C語言型別
    • 當我們需要“兩個位元組的填充符”或者“用四個位元組字串表示的某個東西”時,我們不能使用標準型別,因為在不同的體系架構上,普通C語言的資料型別所佔空間在大小並不相同
    • 核心中的普通記憶體地址通常是unsigned long,在當前Linux支援的所有平臺上,指標和long整形的大小總是相同的
    • C99標準定義了intptr_t和uintptr_t型別,它們是能夠儲存指標值的整形變數
  • 為資料項分配確定的空間大小
    • <asm/types.h>
    • <linux/types.h>
    • u8, s8
    • u16, s16
    • u32, s32
    • u64, s64
    • 如果一個使用者空間程式需要使用這些型別,它可以在名字前加上兩個下劃線作為字首
    • __u8
    • __u32
    • 使用新編譯器的系統將支援C99標準型別,如uint8_t和uint32_t
  • 介面特定的型別
    • 核心中最常用的資料型別由它們自己的typedef宣告,這樣可以防止出現任何移植性問題
    • “介面特定(interface-specific)”是指由某個庫定義的一種資料型別,以便為某個特定的資料結構提供介面
    • 完整的_t型別在<linux/types.h>中定義
    • _t資料項的主要問題是在我們需要列印它們的時候,不太容易選擇正確的printk或者printf的輸出格式
  • 其他有關移植的問題
    • 一個通用的原則是要避免使用顯式的常量值
    • 時間間隔
      • 使用jiffies計算時間間隔的時候,應該用HZ來衡量
    • 頁大小
      • 記憶體頁的大小是PAGE_SIZE位元組
      • PAGE_SHIFT
      • <asm/page.h>
      • getpagesize庫函式
      • get_order函式
    • 位元組序
      • <asm/byteorder.h>
        • __BIG_ENDIAN
        • __LITTLE_ENDIAN
      • u32 cpu_to_le32 (u32);
      • u32 le32_to_cpu(u32);
      • be64_to_cpu
      • le16_to_cpus
      • cpu_to_le32p
    • 資料對齊
      • <asm/unaligned.h>
        • get_unaligned(ptr);
        • put_unaligned(val, ptr);
    • 指標和錯誤值
      • 許多核心介面通過把錯誤值編碼到一個指標值中來返回錯誤資訊
      • <linux/err.h>
        • void *ERR_PTR(long error);
        • long IS_ERR(const void *ptr);
        • long PTR_ERR(const void *ptr);
  • 連結串列
    • <linux/list.h>
      • struct list_head
        • struct list_head *next, *prev;
      • INIT_LIST_HEAD(&list);
      • LIST_HEAD(list);
      • list_add(struct list_head *new, struct list_head *head);
      • list_add_tail(struct list_head *new, struct list_head *head);
      • list_del(struct list_head *entry);
      • list_del_init(struct list_head *entry);
      • list_move(struct list_head *entry, struct list_head *head);
      • list_move_tail(struct list_head *entry, struct list_head *head);
      • list_empty(struct list_head *head);
      • list_splice(struct list_head *list, struct list_head *head);
      • list_entry(struct list_head *ptr, type_of_struct, field_name);
      • list_for_each(struct list_head *cursor, struct list_head *list)
      • list_for_each_prev(struct list_head *cursor, struct list_head *list)
      • list_for_each_safe(struct list_head *cursor, struct list_head *next, struct list_head *list)
      • list_for_each_entry(type *cursor, struct list_head *list, member)
      • list_for_each_entry_safe(type *cursor, type *next, struct list_head *list, member)