• Linux驱动开发——指针和错误值


    参考:

    《Linux设备驱动程序》第三版 P294

      许多内部的内核函数返回一个指针值给调用者,而这些函数中很多可能会失败。在大部分情况下,失败是通过返回一个NULL指针值来表示的。这种技巧有作用,但是它不能传递问题的确切性质。某些接口确实需要返回一个实际的错误编码,以使调用者可以根据实际出错的情况做出正确的决策。

      许多内核接口通过把错误值编码到一个指针值中来返回错误信息。这种函数必须小心使用,因为他们的返回值不能简单地和NULL比较。为了帮助创建和使用这种类型的接口,<linux/err.h>中提供了一小组函数。

      返回指针类型的函数可以通过如下函数返回一个错误值:

        void *ERR_PTR(long err);

      这里error是通常的负的错误编码。调用者可以使用IS_ERR来检查所返回的指针是否是一个错误编码:

        long IS_ERR(const void *ptr);

      如果需要实际的错误编码,可以通过如下函数把它提取出来:

        long PTR_ERR(const void *ptr);

      应该使用IS_ERR对某值返回真值时才对该值使用PTR_ERR,因为任何其他值都是有效指针。

    补充:

    在include/linux/err.h中定义如下几个宏:

    1、void * ERR_PTR(long error):将错误编码转为指针

    2、long PTR_ERR(const void *ptr):将指针转为错误编码

    3、bool IS_ERR(const void *ptr):检查返回指针是否为一个错误编码,如果返回真,表示确实发生了错误

    4、bool IS_ERR_OR_NULL(const void *ptr):检查返回的指针是否为NULL或是否为一个错误编码

    5、int PTR_ERR_OR_ZERO(const void *ptr):将返回的指针转为0或者错误编码

    6、void * ERR_CAST(const void *ptr):将const void *转为void *,防止编译报错

     1 #define MAX_ERRNO    4095
     2 
     3 #define IS_ERR_VALUE(x) unlikely((unsigned long)(void *)(x) >= (unsigned long)-MAX_ERRNO)
     4 
     5 static inline void * __must_check ERR_PTR(long error)
     6 {
     7     return (void *) error;
     8 }
     9 
    10 static inline long __must_check PTR_ERR(__force const void *ptr)
    11 {
    12     return (long) ptr;
    13 }
    14 
    15 static inline bool __must_check IS_ERR(__force const void *ptr)
    16 {
    17     return IS_ERR_VALUE((unsigned long)ptr);
    18 }
    19 
    20 static inline bool __must_check IS_ERR_OR_NULL(__force const void *ptr)
    21 {
    22     return unlikely(!ptr) || IS_ERR_VALUE((unsigned long)ptr);
    23 }
    24 
    25 /**
    26  * ERR_CAST - Explicitly cast an error-valued pointer to another pointer type
    27  * @ptr: The pointer to cast.
    28  *
    29  * Explicitly cast an error-valued pointer to another pointer type in such a
    30  * way as to make it clear that's what's going on.
    31  */
    32 static inline void * __must_check ERR_CAST(__force const void *ptr)
    33 {
    34     /* cast away the const */
    35     return (void *) ptr;
    36 }
    37 
    38 static inline int __must_check PTR_ERR_OR_ZERO(__force const void *ptr)
    39 {
    40     if (IS_ERR(ptr))
    41         return PTR_ERR(ptr);
    42     else
    43         return 0;
    44 }

    示例:

    1、比如函数_devm_regulator_get用于获得指定的regulator指针:

     1 static struct regulator *_devm_regulator_get(struct device *dev, const char *id,
     2                          int get_type)
     3 {
     4     struct regulator **ptr, *regulator;
     5 
     6     ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL);
     7     if (!ptr)
     8         return ERR_PTR(-ENOMEM);
     9 
    10     switch (get_type) {
    11     case NORMAL_GET:
    12         regulator = regulator_get(dev, id);
    13         break;
    14     case EXCLUSIVE_GET:
    15         regulator = regulator_get_exclusive(dev, id);
    16         break;
    17     case OPTIONAL_GET:
    18         regulator = regulator_get_optional(dev, id);
    19         break;
    20     default:
    21         regulator = ERR_PTR(-EINVAL);
    22     }
    23 
    24     if (!IS_ERR(regulator)) {
    25         *ptr = regulator;
    26         devres_add(dev, ptr);
    27     } else {
    28         devres_free(ptr);
    29     }
    30 
    31     return regulator;
    32 }

    第7行返回NULL,表示内存分配失败,但是由于该函数需要返回的是指针类型,所以我们用ERR_PTR对-ENOMEM进行包装

    第21行,表示传入的参数不合法,此时用ERR_PTR对-EINVAL进行包装

    下面是调用devm_regulator_get的地方:

    1     case snd_soc_dapm_regulator_supply:
    2         w->regulator = devm_regulator_get(dapm->dev, w->name);
    3         if (IS_ERR(w->regulator)) {
    4             ret = PTR_ERR(w->regulator);
    5             dev_err(dapm->dev, "ASoC: Failed to request %s: %d
    ",
    6                 w->name, ret);
    7             return NULL; 
    8         }

    第3行,如果IS_ERR返回指针确实是一个错误编码对应的指针,第4行就会用PTR_ERR将该指针转为一个错误编码给ret,后面可以根据需要处理该ret。

    第7行,除了使用return NULL之外,还可以使用ERR_CAST(w->regulator)

     

    完。

  • 相关阅读:
    [USACO09Open] Tower of Hay 干草塔
    [HNOI2004]打鼹鼠
    BZOJ1222[HNOI 2001]产品加工
    BZOJ1270[BJWC2008]雷涛的小猫
    NOIP2018出征策
    解析·NOIP·冷门 CLZ最小环
    CCF-NOIP-2018 提高组(复赛) 模拟试题(九)(2018 CSYZ长沙一中)
    [脚本无敌1]图片批量处理(matlab)
    用Matlab解《2013年数据建模比赛》图像碎片拼接题
    火灾检测-fire,fire
  • 原文地址:https://www.cnblogs.com/pengdonglin137/p/7596979.html
Copyright © 2020-2023  润新知