对内核源码中IS_ERR的理解

来源:互联网 发布:数据结构和算法java版 编辑:程序博客网 时间:2024/06/05 19:29

  今天在看内核源码时,看到一个判断指针是否是错误指针或无效指针的函数IS_ERR(2.6.11内核,include/linux/err.h中),其源码如下:   

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;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,现在还不知道,知道的同学可以留个言,共同学习。

另外本人的表达能力不好,如果有什么疑惑也可以留言,交流一下。


 

原创粉丝点击