对内核源码中IS_ERR的理解
来源:互联网 发布:ps淘宝主图怎么修改 编辑:程序博客网 时间:2024/06/02 04:19
转载自http://blog.csdn.net/moonvs2010/article/details/7790422 作者:moonvs2010
今天在看内核源码时,看到一个判断指针是否是错误指针或无效指针的函数IS_ERR(2.6.11内核,include/linux/err.h中),其源码如下:
- static inlinelong IS_ERR(constvoid *ptr)
- {
- return unlikely((unsignedlong)ptr > (unsigned long)-1000L);
- }
static inline long IS_ERR(const void *ptr){return unlikely((unsigned long)ptr > (unsigned long)-1000L);}
这个函数非常简单,只是将指针的值和-1000L进行比较,如果ptr的值大于(unsigned long)-1000L,则表示ptr是一个无效指针或错误指针。很奇怪,不知道为什么要和-1000L进行比较,所以进行一番搜索和学习,现将自己的理解整理一下,记录下来,跟大家分享一下。
Linux中的指针分为三类:有效指针、空指针(NULL, 通常为0)和无效指针(错误指针)。这里只关心无效指针,什么样的指针式无效指针?根据IS_ERR的判断,如果指针的值大于(unsigned long)-1000L,则这个指针是无效指针。将-1000L通过十六进制输出其值为0xfffffc18,这个值刚好在0xfffff000到0xffffffff之间,而这个区间正好是32位下4G内存空间的最后一页。根据查阅的资料,之前版本的内核不是和-1000L比较,而是和-4095比较,也就是说指针的值只要是在最后一页就认为是无效指针。所以Linux是将最后一页作为来判定是否是错误指针来使用的,当然现在的范围只是最后一页的一部分0xfffffc18到0xffffffff之间,根据include/linux/err.h文件的注释,Linux内核中返回的无效指针中包含更多的信息,包含错误码或者一个目录项指针。
先看下面的一个函数,
- struct net_device * __init el1_probe(int unit)
- {
- struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
- static unsigned ports[] = { 0x280, 0x300, 0};
- unsigned *port;
- int err = 0;
- <SPAN style="COLOR: #ff0000"><STRONG>if (!dev)
- return ERR_PTR(-ENOMEM);</STRONG>
- </SPAN>
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- io = dev->base_addr;
- irq = dev->irq;
- mem_start = dev->mem_start & 7;
- }
- SET_MODULE_OWNER(dev);
- if (io > 0x1ff) {/* Check a single specified location. */
- err = el1_probe1(dev, io);
- } else if (io != 0) {
- err = -ENXIO; /* Don't probe at all. */
- } else {
- for (port = ports; *port && el1_probe1(dev, *port); port++)
- ;
- if (!*port)
- err = -ENODEV;
- }
- if (err)
- goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
- return dev;
- out1:
- release_region(dev->base_addr, EL1_IO_EXTENT);
- out:
- free_netdev(dev);
- return ERR_PTR(err);
- }
struct net_device * __init el1_probe(int unit){struct net_device *dev = alloc_etherdev(sizeof(struct net_local));static unsigned ports[] = { 0x280, 0x300, 0};unsigned *port;int err = 0;if (!dev)return ERR_PTR(-ENOMEM);if (unit >= 0) {sprintf(dev->name, "eth%d", unit);netdev_boot_setup_check(dev);io = dev->base_addr;irq = dev->irq;mem_start = dev->mem_start & 7;}SET_MODULE_OWNER(dev);if (io > 0x1ff) {/* Check a single specified location. */err = el1_probe1(dev, io);} else if (io != 0) {err = -ENXIO;/* Don't probe at all. */} else {for (port = ports; *port && el1_probe1(dev, *port); port++);if (!*port)err = -ENODEV;}if (err)goto out;err = register_netdev(dev);if (err)goto out1;return dev;out1:release_region(dev->base_addr, EL1_IO_EXTENT);out:free_netdev(dev);return ERR_PTR(err);}
主要看红色的部分,当dev分配失败时,返回的是ERR_PTR(-ENOMEM),相当于是(void *)(-ENOMEM),而这个返回的指针的值转换成16进制后也落在这个值刚好在0xfffffc18到0xffffffff之间。所以当Linux判断一个指针是一个无效指针时,仅仅通过这个无效的指针就可以拿到错误码,知道错误原因,而不需要用另一个变量来返回错误原因。其实说了那么一大堆废话,就是想引出这个结论。平时在写程序时,如果需要某个函数返回一个指针,发生错误时返回NULL,但仅仅知道一个NULL,是不能判断究竟发生了什么错误,还需要另外一个位置来存储错误,从这点就可以看出内核设计的一些细节非常值得我们学习和借鉴。
如果目录项的指针位于0xfffffc18到0xffffffff之间,也表示这个目录项指针是一个无效指针,因为最后一页是不使用的,用来标示错误。至于内核为什么把范围的起始地址从0xfffff000该为0xfffffc18,现在还不知道,知道的同学可以留个言,共同学习。
另外本人的表达能力不好,如果有什么疑惑也可以留言,交流一下。
- 对内核源码中IS_ERR的理解
- 对内核源码中IS_ERR的理解
- Linux中IS_ERR()函数的理解
- Linux中IS_ERR()函数的理解
- 个人--对编译内核源码的理解
- IS_ERR 理解
- 内核中判断返回指针是否错误的方法:使用IS_ERR或者IS_ERR_OR_NULL
- linux内核中的IS_ERR
- linux内核中的IS_ERR
- linux内核中的IS_ERR
- linux内核中的IS_ERR
- linux内核中的IS_ERR
- 内核IS_ERR宏解析
- 对linux内核中jiffies、Hz的理解
- 对浏览器内核的理解?
- 学习笔记 --- LINUX内核里面的IS_ERR宏解析
- [linux device driver] Chapter 03:IS_ERR的理解
- 对linux 0.11版本中进程调度源码的理解
- 在IntelliJ IDEA环境下创建第一个Grails项目
- LIBSVM
- 先锋机器人Aria sdk 参数传递
- unordered
- 字符编码笔记:ASCII,Unicode和UTF-8
- 对内核源码中IS_ERR的理解
- C++模板写的一个单例设计模式类
- Eclipse 下 Android NDK Debug 配置
- 用vc画三角形并填充
- Access数据库列名大小写转换(2012.11.29)
- Windows CE内存管理
- 苦中作乐
- 第十四周上机任务(数组大折腾)!!!
- 订阅任务的查询条件定义面板的发开感悟