天天看點

ERR_PTR,PTR_ERR還有IS_ERR函數詳解

    核心中的函數常常傳回指針,問題是如果出錯,也希望能夠通過傳回的指針展現出來。 總體來說,如果核心傳回一個指針,那麼有三種情況:合法指針,NULL指針和非法指針。

1)合法指針:核心傳回的指針一般是指向頁面的邊界(4K邊界),即 ptr & 0xfff == 0

2)非法指針:這樣ptr的值不可能落在(0xfffff000,0xffffffff)之間(這個區間是核心高端記憶體所在的區間,關于使用者空間和核心空間,可以看考這裡。), 而一般核心的出錯代碼也是一個小負數,在-1000到0之間,轉變成unsigned long,正好在(0xfffff000,0xffffffff)之間。是以可以用 

(unsigned long)ptr > (unsigned long)-1000L

-1000L=0xfffff000

3)利用非法指針,進行錯誤分類:

    來判斷核心函數的傳回值是一個有效的指針,還是一個出錯代碼。 

    MAX_ERRNO了嗎?一個宏,定義為4095,MAX_ERRNO就是最大錯誤号,Linux核心中,出錯有多種可能.

關于Linux核心中的錯誤,我們看一下include/asm-generic/errno-base.h檔案:

#define EPERM 1

#define ENOENT 2

#define ESRCH 3

#define EINTR 4

#define EIO 5

#define ENXIO 6

#define E2BIG 7

#define ENOEXEC 8

#define EBADF 9

#define ECHILD 10

#define EAGAIN 11

#define ENOMEM 12

#define EACCES 13

#define EFAULT 14

#define ENOTBLK 15

#define EBUSY 16

#define EEXIST 17

#define EXDEV 18

#define ENODEV 19

#define ENOTDIR 20

#define EISDIR 21

#define EINVAL 22

#define ENFILE 23

#define EMFILE 24

#define ENOTTY 25

#define ETXTBSY 26

#define EFBIG 27

#define ENOSPC 28

#define ESPIPE 29

#define EROFS 30

#define EMLINK 31

#define EPIPE 32

#define EDOM 33

#define ERANGE 34

最常見的幾個是-EBUSY,-EINVAL,-ENODEV,-EPIPE,-EAGAIN,-ENOMEM,我相信不用說你寫過代碼調試過代碼,隻要你使用過Linux就有可能見過這幾個錯誤,因為它們确實經常出現.這些是每個體系結構裡都有的,另外各個體系結構也都定義了自己的一些錯誤代碼.這些東西當然也都是宏,實際上對應的是一些數字,這個數字就叫做錯誤号.而對于Linux核心來說,不管任何體系結構,最多最多,錯誤号不會超過4095.而4095又正好是比4k小1,即4096減1.而我們知道一個page可能是4k,也可能是更多,比如8k,但至少它也是4k,是以留出一個page出來就可以讓我們把核心空間的指針來記錄錯誤了.什麼意思呢?比如我們這裡的IS_ERR(),它就是判斷kthread_run()傳回的指針是否有錯,如果指針并不是指向最後一個page,那麼沒有問題,申請成功了,如果指針指向了最後一個page,那麼說明實際上這不是一個有效的指針,這個指針裡儲存的實際上是一種錯誤代碼.而通常很常用的方法就是先用IS_ERR()來判斷是否是錯誤,然後如果是,那麼就調用PTR_ERR()來傳回這個錯誤代碼.隻不過咱們這裡,沒有調用PTR_ERR()而已,因為起決定作用的還是IS_ERR(),而PTR_ERR()隻是傳回錯誤代碼,也就是提供一個資訊給調用者,如果你隻需要知道是否出錯,而不在乎因為什麼而出錯,那你當然不用調用PTR_ERR()了

外部參考:http://blog.163.com/arm_linux_learn/blog/static/1921553082011102843732189/

繼續閱讀