很多时候我们在使用 errno 的时候都知道它代表的是 errno.h 中的错误值,可是为什么它就是代表那些值的呢?系统在哪里给它赋值了呢?故事就要从源头开始:
1、errno 全局变量是在哪里定义的?
答:既然是 errno,那一定是和 err 有关的,搜索发现就在 <bits/errno.h> 中有这么一段说明:
# ifndef __ASSEMBLER__
/* Function to get address of global `errno' variable. */
extern int *__errno_location (void) __THROW __attribute__ ((__const__));
# if !defined _LIBC || defined _LIBC_REENTRANT
/* When using threads, errno is a per-thread value. */
# define errno (*__errno_location ())
# endif
# endif /* !__ASSEMBLER__ */
#endif /* _ERRNO_H */
其他先不管,首先我们找到了一个头,那就是 errno 就是 (*__errno_location()),说白了就是函数 __errno_location() 的
返回值
,结合前面知道 errno 是
int 型整数
,线索慢慢开始了
2、我们开始去 glibc 即 Linux 源代码中查找 __errno_location() 函数,结果在 errno-loc.c 中有了解释,就一段:
#include <errno.h>
#include <hurd/threadvar.h>
int *
__errno_location (void)
{
return (int *) __hurd_threadvar_location (_HURD_THREADVAR_ERRNO);
}
strong_alias (__errno_location, __hurd_errno_location)
libc_hidden_def (__errno_location)
意思很明确我
__errno_location()
函数的返回值就是
__hurd_threadvar_location (_HURD_THREADVAR_ERRNO)
函数的返回值被强转成 int * 了,那
__hurd_threadvar_location (_HURD_THREADVAR_ERRNO)
又是什么函数呢?
3、同样搜索
__hurd_threadvar_location
函数,结果没找到,怎么办?通过查看
__errno_location()
函数头文件发现 <hurd/threadvar.h> 似乎好像有点关系,直接找到查看发现这么一段:
#include <machine-sp.h> /* Define __thread_stack_pointer. */
/* Return the location of the current thread's value for the
per-thread variable with index INDEX. */
extern unsigned long int *
__hurd_threadvar_location (enum __hurd_threadvar_index __index) __THROW
/* This declaration tells the compiler that the value is constant
given the same argument. We assume this won't be called twice from
the same stack frame by different threads. */
__attribute__ ((__const__));
_HURD_THREADVAR_H_EXTERN_INLINE unsigned long int *
__hurd_threadvar_location (enum __hurd_threadvar_index __index)
{
return __hurd_threadvar_location_from_sp (__index,
__thread_stack_pointer ());
}
这是先定义了函数同时在下面直接就给出了函数代码,这个函数的又是调用了
__hurd_threadvar_location_from_sp (__index, __thread_stack_pointer ())
这个函数,还有一点
_HURD_THREADVAR_H_EXTERN_INLINE
这是什么?(这个其实可以忽略的,因为前面声明了函数是
extern unsigned long int *
)
注*:在前面有定义
#define _HURD_THREADVAR_H_EXTERN_INLINE extern __inline
了解到其实就是 extern __inline ,其中 ___inline 表示函数是内联函数,没其他功效,在这里我们直接忽略
4、我们同样在<hurd/threadvar.h> 中往前看,有这样的代码:
extern unsigned long int *__hurd_threadvar_location_from_sp
(enum __hurd_threadvar_index __index, void *__sp);
_HURD_THREADVAR_H_EXTERN_INLINE unsigned long int *
__hurd_threadvar_location_from_sp (enum __hurd_threadvar_index __index,
void *__sp)
{
unsigned long int __stack = (unsigned long int) __sp;
return &((__stack >= __hurd_sigthread_stack_base &&
__stack < __hurd_sigthread_stack_end)
? __hurd_sigthread_variables
: (unsigned long int *) ((__stack & __hurd_threadvar_stack_mask) +
__hurd_threadvar_stack_offset))[__index];
}
真相似乎已经越来越近了,我们只需要弄清楚一下内容,结果就呼之欲出了:
- __hurd_threadvar_index __index 是什么?
- __sp 是一个 void * 指针?
- __hurd_sigthread_stack_base 是什么?
- __hurd_sigthread_stack_end 是什么?
- __hurd_sigthread_variables 是什么?
- __hurd_threadvar_stack_mask 是什么?
- __hurd_threadvar_stack_offset 是什么?
5、往前有定义
enum __hurd_threadvar_index
{
_HURD_THREADVAR_MIG_REPLY, /* Reply port for MiG user stub functions. */
_HURD_THREADVAR_ERRNO, /* `errno' value for this thread. */
_HURD_THREADVAR_SIGSTATE, /* This thread's `struct hurd_sigstate'. */
_HURD_THREADVAR_DYNAMIC_USER, /* Dynamically-assigned user variables. */
_HURD_THREADVAR_MALLOC, /* For use of malloc. */
_HURD_THREADVAR_DL_ERROR, /* For use of -ldl and dynamic linker. */
_HURD_THREADVAR_RPC_VARS, /* For state of RPC functions. */
_HURD_THREADVAR_LOCALE, /* For thread-local locale setting. */
_HURD_THREADVAR_CTYPE_B, /* Cache of thread-local locale data. */
_HURD_THREADVAR_CTYPE_TOLOWER, /* Cache of thread-local locale data. */
_HURD_THREADVAR_CTYPE_TOUPPER, /* Cache of thread-local locale data. */
_HURD_THREADVAR_MAX /* Default value for __hurd_threadvar_max. */
};
再从前面
__hurd_threadvar_location (_HURD_THREADVAR_ERRNO)
传过来的参数,知道
__hurd_threadvar_location_from_sp (enum __hurd_threadvar_index __index, void *__sp)
函数第一个参数是
_HURD_THREADVAR_ERRNO
,第二个参数在
__sp
指向
__thread_stack_pointer ()
函数的返回值,查询
<machine-sp.h>
有如下:
_EXTERN_INLINE void *
__thread_stack_pointer (void)
{
register void *__sp__;
__asm__ ("mr %0, 1" : "=r" (__sp__));
return __sp__;
}
关于以上的返回值,不好意思目前还没学到看不懂,后期接触到了补上。
6、继续
cdefg
中的变量在前面声明了:
extern unsigned long int __hurd_threadvar_stack_mask;
extern unsigned long int __hurd_threadvar_stack_offset;
extern unsigned long int __hurd_threadvar_stack_mask;
extern unsigned long int __hurd_threadvar_stack_offset;
extern unsigned long int __hurd_sigthread_stack_base;
extern unsigned long int __hurd_sigthread_stack_end;
extern unsigned long int *__hurd_sigthread_variables;
以下是上面变量的注释:
/* The per-thread variables are found by ANDing this mask
with the value of the stack pointer and then adding this offset.
In the multi-threaded case, cthreads initialization sets
__hurd_threadvar_stack_mask to ~(cthread_stack_size - 1), a mask which
finds the base of the fixed-size cthreads stack; and
__hurd_threadvar_stack_offset to a small offset that skips the data
cthreads itself maintains at the base of each thread's stack.
In the single-threaded case, __hurd_threadvar_stack_mask is zero, so the
stack pointer is ignored; and __hurd_threadvar_stack_offset gives the
address of a small allocated region which contains the variables for the
single thread. */
/* A special case must always be made for the signal thread. Even when there
is only one user thread and an allocated region can be used for the user
thread's variables, the signal thread needs to have its own location for
per-thread variables. The variables __hurd_sigthread_stack_base and
__hurd_sigthread_stack_end define the bounds of the stack used by the
signal thread, so that thread can always be specifically identified. */
/* At the location described by the two variables above,
there are __hurd_threadvar_max `unsigned long int's of per-thread data. */
没时间翻译了
7、解释一下
return &((__stack >= __hurd_sigthread_stack_base && __stack < __hurd_sigthread_stack_end) ? __hurd_sigthread_variables : (unsigned long int *) ((__stack & __hurd_threadvar_stack_mask) + __hurd_threadvar_stack_offset))[__index]
的意思:
首先返回一个地址
该地址要么是
__hurd_sigthread_variables
要么是
(unsigned long int *) ((__stack & __hurd_threadvar_stack_mask) + __hurd_threadvar_stack_offset))[__index]
如果
__hurd_sigthread_stack_base<=__stack < __hurd_sigthread_stack_end
为真,则取前者的地址,否者取后者的地址
__stack & __hurd_threadvar_stack_mask
这是一个二进制 与 运算
(unsigned long int *) ((__stack & __hurd_threadvar_stack_mask) + __hurd_threadvar_stack_offset))[__index]
等同于
(unsigned long int *)(&__hurd_threadvar_stack_offset[__stack & __hurd_threadvar_stack_mask][_HURD_THREADVAR_ERRNO])