linux 错误编号使用

#define MAX_ERRNO	4095
#define	EINVAL		22	/* Invalid argument */

#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)

static inline bool __must_check IS_ERR(__force const void *ptr)
{
	return IS_ERR_VALUE((unsigned long)ptr);
}

static inline void * __must_check ERR_PTR(long error)
{
	return (void *) error;
}

//函数返回值使用
return ERR_PTR(-EINVAL);

//判断函数返回值
if (!IS_ERR(p)) {
    ...
}

1. 

在 Linux 内核编程中,__must_check 是一个被广泛使用的标志,它被用于告诉编译器和程序员,某个函数的返回值必须被检查。

__must_check 是一个宏,定义在 include/linux/compiler.h 文件中,它的定义如下:

#define __must_check		__attribute__((warn_unused_result))

__attribute__((warn_unused_result)) 是 GCC 扩展的属性,其意义是如果函数的返回值没有被使用,那么编译器在编译时会发出警告。 在实际的 Linux 内核编程中,我们通常在那些 failure-prone 的系统调用函数 (比如 malloc()) 的定义上面标注 __must_check。这样做的目的是为了提醒使用这些函数的开发者注意检查这些函数的返回值,因为它们可能会失败,如果忽视了这些函数的返回值,可能会导致严重的结果。

2.

在 Linux 内核中,指针不仅可以用来引用具体的地址,也可以用来表达错误编号。这是因为 Linux 内核将高端地址用于表示错误编号,这样可以节省空间,没有必要为错误编号再定义一种数据结构。

IS_ERR_VALUE 这个宏的目的就是来检测一个给定的值是否可能是一个错误值。

看一下这个定义 #define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)

它判断的是x的值(我们通常传入的是转换为unsigned long类型的指针)是否大于等于 (unsigned long)-MAX_ERRNO

这里有几个点需要理解:

  1. MAX_ERRNO 值为 4095,这是 Linux kernel 定义的最大错误编号,这样就可以确保错误编号都在有效范围内。
  2. -(MAX_ERRNO) 就是 -4095,对其进行无符号长整型转换,转化为 (unsigned long)-4095 (是一个非常大的数,因为是转化为了无符号数值)。
  3. 假设 x 是一个错误值,由内核进行如下转化 PTR_ERR(ERR_PTR(error code)) (PTR_ERR 和 ERR_PTR 是一对宏,用来在指针和错误码之间进行转换)。那么它就会被转化为一个大于等于 (unsigned long)-4095 的数值,也就是返回真 (true),表示 x 是一个错误值。

所以这个宏就是用来判断一个给定的(转换为 unsigned long 后的)值是否在可能的错误值范围内,如果在,那就认定它是一个错误值。