linux内核中的IS_ERR
[plain]view plaincopyprint?
- asmlinkageintsys_execve(char__user*filenamei,char__user*__user*argv,
- char__user*__user*envp,structpt_regs*regs)
- {
- interror;
- char*filename;
- filename=getname(filenamei);
- error=PTR_ERR(filename);
- if(IS_ERR(filename))
- gotoout;
- error=do_execve(filename,argv,envp,regs);
- putname(filename);
- out:
- returnerror;
- }
[plain]view plaincopyprint?
- #ifndef_LINUX_ERR_H
- #define_LINUX_ERR_H
- #include
- #include
- /*
- *Kernelpointershaveredundantinformation,sowecanusea
- *schemewherewecanreturneitheranerrorcodeoradentry
- *pointerwiththesamereturnvalue.
- *
- *Thisshouldbeaper-architecturething,toallowdifferent
- *errorandpointerdecisions.
- */
- #defineIS_ERR_VALUE(x)unlikely((x)>(unsignedlong)-1000L)
- staticinlinevoid*ERR_PTR(longerror)
- {
- return(void*)error;
- }
- staticinlinelongPTR_ERR(constvoid*ptr)
- {
- return(long)ptr;
- }
- staticinlinelongIS_ERR(constvoid*ptr)
- {
- returnIS_ERR_VALUE((unsignedlong)ptr);
- }
- #endif/*_LINUX_ERR_H*/
要想明白IS_ERR(),首先理解要内核空间。所有的驱动程序都是运行在内核空间,内核空间虽然很大,但总是有限的,而在这有限的空间中,其最后一个page是专门保留的,也就是说一般人不可能用到内核空间最后一个page的指针。换句话说,你在写设备驱动程序的过程中,涉及到的任何一个指针,必然有三种情况:
- 有效指针;
- NULL,空指针;
- 错误指针,或者说无效指针。
而所谓的错误指针就是指其已经到达了最后一个page,即内核用最后一页捕捉错误。比如对于32bit的系统来说,内核空间最高地址0xffffffff,那么最后一个page就是指的0xfffff000~0xffffffff(假设4k一个page),这段地址是被保留的。内核空间为什么留出最后一个page?我们知道一个page可能是4k,也可能是更多,比如8k,但至少它也是4k,所以留出一个page出来就可以让我们把内核空间的指针来记录错误了。内核返回的指针一般是指向页面的边界(4k边界),即ptr & 0xfff == 0。如果你发现你的一个指针指向这个范围中的某个地址,那么你的代码肯定出错了。IS_ERR()就是判断指针是否有错,如果指针并不是指向最后一个page,那么没有问题;如果指针指向了最后一个page,那么说明实际上这不是一个有效的指针,这个指针里保存的实际上是一种错误代码。而通常很常用的方法就是先用IS_ERR()来判断是否是错误,然后如果是,那么就调用PTR_ERR()来返回这个错误代码。因此,判断一个指针是不是有效的,可用如下的方式:
#define IS_ERR_VALUE(x) unlikely((x) > (unsigned long)-1000L)
(unsigned long)-1000L 应该为 (unsigned long)-0x1000L!(因为 -0x1000 才是 0xFFFFF000),这应该是内核的一个bug吧!在2.6.30.4的内核中是这样定义的:
[plain]view plaincopyprint?
- #defineMAX_ERRNO4095
- #defineIS_ERR_VALUE(x)unlikely((x)>=(unsignedlong)-MAX_ERRNO)
即判断是不是在(0xfffff000,0xffffffff)之间,因此,可以用IS_ERR()来判断内核函数的返回值是不是一个有效的指针。注意这里用unlikely()的用意!
至于PTR_ERR(), ERR_PTR(),只是强制转换以下而已。现在应该知道为什么我写返回错误码的时候也加个负号如 -ENOSYS这样子了。而PTR_ERR()只是返回错误代码,也就是提供一个信息给调用者,如果你只需要知道是否出错,而不在乎因为什么而出错,那你当然不用调用PTR_ERR()了。
而我们的错误码的值在内存中定义都是这样的(asm-generic/errno-base.h):
[plain]view plaincopyprint?
- ......
- #defineEPERM1/*Operationnotpermitted*/
- #defineENOENT2/*Nosuchfileordirectory*/
- #defineESRCH3/*Nosuchprocess*/
- #defineEINTR4/*Interruptedsystemcall*/
- #defineEIO5/*I/Oerror*/
- #defineENXIO6/*Nosuchdeviceoraddress*/
- #defineE2BIG7/*Argumentlisttoolong*/
- #defineENOEXEC8/*Execformaterror*/
- #defineEBADF9/*Badfilenumber*/
- #defineECHILD10/*Nochildprocesses*/
- #defineEAGAIN11/*Tryagain*/
- #defineENOMEM12/*Outofmemory*/
- #defineEACCES13/*Permissiondenied*/
- #defineEFAULT14/*Badaddress*/
- #defineENOTBLK15/*Blockdevicerequired*/
- #defineEBUSY16/*Deviceorresourcebusy*/
- #defineEEXIST17/*Fileexists
linux内核IS_ER 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)