linux內核中的IS_ERR()、PTR_ERR()、ERR_PTR()

linux內核中的IS_ERR()、PTR_ERR()、ERR_PTR()

IS_ERR宏定義在include/linux/err.h,如下所示:

#define MAX_ERRNO 4095

//判斷x是不是在(0xfffff000,0xffffffff)之間,注意這裏用unlikely()的用意
#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
  
//由錯誤碼求指針,-1 -> 0xFFFFFFFF
static inline void *ERR_PTR(long error)  
{  
    return (void *) error;  
}  

//由指針求錯誤碼,0xFFFFFFFF -> -1 ,依次類推
static inline long PTR_ERR(const void *ptr)  
{  
    return (long) ptr;  
}  
  
//判斷x是不是在(0xfffff000,0xffffffff)之間,x是不是一個有效的指針
static inline long IS_ERR(const void *ptr)  
{  
    return IS_ERR_VALUE((unsigned long)ptr);  
}  
  
    要想明白IS_ERR(),首先要理解內核空間,所有的驅動程序都運行在內核空間。內核空間雖然很大,但總是有限的。在這有限的空間中,其最後一個page是專門爲錯誤碼保留的,即內核用最後一頁捕捉錯誤,一般人不可能用到內核空間最後一個page的指針。因此,在寫設備驅動程序的過程中,涉及到的指針,必然有以下三種情況:有效指針;NULL,即空指針;錯誤指針,或者說無效指針。
    
    而所謂的錯誤指針就是指其已經到達了最後一個page。比如,對於32位的系統,內核空間最高地址爲0xffffffff,那麼最後一個page就是0xfffff000到 0xffffffff(假設4k一個page),這段地址是被保留的。如果你發現你的一個指針指向這個範圍中的某個地址,那麼你的代碼肯定出錯了。
    
    IS_ERR()就是用來判斷指針是否有錯,如果指針並不是指向最後一個page,那麼沒有問題;如果指針指向了最後一個page,那麼說明實際上這不是一個有效的指針,這個指針裏保存的實際上是一種錯誤代碼。而通常很常用的方法就是先用IS_ERR()來判斷是否是錯誤,然後如果是,那麼就調用PTR_ERR()來返回這個錯誤代碼。

    錯誤碼的值在內存中的定義(asm-generic/errno-base.h):

#define EPERM        1  /* Operation not permitted */  
#define ENOENT       2  /* No such file or directory */  
#define ESRCH        3  /* No such process */  
#define EINTR        4  /* Interrupted system call */  
#define EIO       5  /* I/O error */  
#define ENXIO        6  /* No such device or address */  
#define E2BIG        7  /* Argument list too long */  
#define ENOEXEC      8  /* Exec format error */  
#define EBADF        9  /* Bad file number */  
#define ECHILD      10  /* No child processes */  
#define EAGAIN      11  /* Try again */  
#define ENOMEM      12  /* Out of memory */  
#define EACCES      13  /* Permission denied */  
#define EFAULT      14  /* Bad address */  
#define ENOTBLK     15  /* Block device required */  
#define EBUSY       16  /* Device or resource busy */  
#define EEXIST      17  /* File exists */  
#define EXDEV       18  /* Cross-device link */  
#define ENODEV      19  /* No such device */  
#define ENOTDIR     20  /* Not a directory */  
#define EISDIR      21  /* Is a directory */  
#define EINVAL      22  /* Invalid argument */  
#define ENFILE      23  /* File table overflow */  
#define EMFILE      24  /* Too many open files */  
#define ENOTTY      25  /* Not a typewriter */  
#define ETXTBSY     26  /* Text file busy */  
#define EFBIG       27  /* File too large */  
#define ENOSPC      28  /* No space left on device */  
#define ESPIPE      29  /* Illegal seek */  
#define EROFS       30  /* Read-only file system */  
#define EMLINK      31  /* Too many links */  
#define EPIPE       32  /* Broken pipe */  
#define EDOM        33  /* Math argument out of domain of func */  
#define ERANGE      34  /* Math result not representable */  

    如果指針指向了最後一個page,那麼說明實際上這不是一個有效的指針。這個指針裏保存的實際上是一種錯誤代碼。而通常很常用的方法就是先用IS_ERR()來判斷是否是錯誤,然後如果是,那麼就調用PTR_ERR()來返回這個錯誤代碼。返回錯誤碼的時候一般加個負號,如-ENOSYS。
發佈了8 篇原創文章 · 獲贊 3 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章