本文介紹Linux 4.4內(nèi)核IS_ERR()函數(shù)。
文件:include/linux/err.h,定義如下:
#define MAX_ERRNO 4095
## 對(duì)于64位系統(tǒng),判斷x是否在0xffff ffff ffff f001 ~ 0xffff ffff ffff ffff
#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
static inline long __must_check PTR_ERR(__force const void *ptr)
{
return (long) ptr;
}
static inline bool __must_check IS_ERR(__force const void *ptr)
{
return IS_ERR_VALUE((unsigned long)ptr);
}
一、功能
功能:判斷傳入的指針ptr是否有效。
Linux內(nèi)核指針包括:有效指針、空指針(NULL)和錯(cuò)誤指針。
Linux內(nèi)核用最后4K空間保存指針的出錯(cuò)碼,64位的系統(tǒng)地址為:0xffff ffff ffff f001 ~ 0xffff ffff ffff ffff。
如果是錯(cuò)誤指針,配合PTR_ERR()函數(shù)判斷錯(cuò)誤代碼。
文件:include/uapi/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 */
...
文件:include/uapi/asm-generic/errno.h,定義如下:
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
#define ENOSYS 38 /* Invalid system call number */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
...
文件:include/linux/errno.h,定義如下:
#define ERESTARTSYS 512
#define ERESTARTNOINTR 513
#define ERESTARTNOHAND 514 /* restart if no handler.. */
#define ENOIOCTLCMD 515 /* No ioctl command */
#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
#define EPROBE_DEFER 517 /* Driver requests probe retry */
...
二、說明
1)inline:內(nèi)聯(lián)函數(shù)。內(nèi)聯(lián)函數(shù)的代碼會(huì)直接嵌入到調(diào)用它的位置,調(diào)用幾次就嵌入幾次。
2)__must_check:指調(diào)用函數(shù)一定要處理函數(shù)的返回值,否則編譯器會(huì)給出警告。
3)__force:表示變量可進(jìn)行強(qiáng)制轉(zhuǎn)換。
4)unlikely后續(xù)專門介紹。
4)(unsigned long)-MAX_ERRNO:用補(bǔ)碼的方式表示-4095,64位系統(tǒng)為0xffff ffff ffff f001。
三、示例
文件:drivers/gpu/drm/rockchip/rockchip_drm_drv.c
printk(KERN_ERR" ==== unsigned long 0x%lx \n", (unsigned long)-MAX_ERRNO);
...
private->devfreq = devfreq_get_devfreq_by_phandle(dev, 0);
printk(KERN_ERR"==== IS_ERR(private->devfreq) %d , private->devfreq %p\n", \
IS_ERR(private->devfreq), private->devfreq);
## 1、判斷是否有效指針
if (IS_ERR(private->devfreq)) {
## 2、判斷錯(cuò)誤碼
if (PTR_ERR(private->devfreq) == -EPROBE_DEFER) {
parent_np = of_parse_phandle(np, "devfreq", 0);
if (parent_np &&
of_device_is_available(parent_np)) {
...
} else {
## 3、運(yùn)行到此處
dev_info(dev, "dmc is disabled\n");
}
} else {
...
}
...
}
...
private->hdmi_pll.pll = devm_clk_get(dev, "hdmi-tmds-pll");
printk(KERN_ERR"==== IS_ERR(private->hdmi_pll.pll) %d , private->hdmi_pll.pll %p\n", \
IS_ERR(private->hdmi_pll.pll), private->hdmi_pll.pll);
程序運(yùn)行后,相關(guān)日志如下:
[ 2.270871] ==== unsigned long 0xfffffffffffff001
[ 2.271322] ==== IS_ERR(private->devfreq) 1 , private->devfreq fffffffffffffdfb
[ 2.271993] rockchip-drm display-subsystem: dmc is disabled
[ 2.272504] ==== IS_ERR(private->hdmi_pll.pll) 0 , private->hdmi_pll.pll ffffffc0782e6340
通過上面日志可以看出:
1)private->devfreq值為0xfffffffffffffdfb(值為-517),對(duì)應(yīng)錯(cuò)誤碼EPROBE_DEFER,此時(shí)IS_ERR返回1。
2)private->hdmi_pll.pll值為0xffffffc0782e6340,是有效指針,IS_ERR返回0。