在阅读“理解Linux内核”时,我发现union被用于进程描述符数据结构。
union thread_union {
struct thread_info thread_info;
unsigned long stack[2048]; /* 1024 for 4KB stacks */
};
为什么在这里使用union,对于同时使用两个数据结构的union thread_union
?
在阅读“理解Linux内核”时,我发现union被用于进程描述符数据结构。
union thread_union {
struct thread_info thread_info;
unsigned long stack[2048]; /* 1024 for 4KB stacks */
};
为什么在这里使用union,对于同时使用两个数据结构的union thread_union
?
union thread_union {
struct thread_info thread_info;
unsigned long stack[THREAD_SIZE/sizeof(long)];
};
在内核中定义(参见include/linux/sched.h
)。这很重要,因为宏THREAD_SIZE
在许多地方使用(总体上在内核源代码中使用了几百次),并且在不同的架构之间有所不同。
楼主想知道为什么不使用结构体:
struct thread_struct {
struct thread_info thread_info;
unsigned long stack[(THREAD_SIZE - sizeof (struct thread_info))/sizeof (long)];
};
init_thread_info
和init_stack
已经相应地进行了调整,即两者都引用init_thread_union
的开头,以便实际内存布局不会改变。)init/init_task.c
中定义了一个这种联合类型的init_thread_union
变量,用于引导时的初始内核线程,并且预处理器宏。#define init_thread_info (init_thread_union.thread_info)
#define init_stack (init_thread_union.stack)
在特定于架构的头文件中(例如,在x86上的{{link1:arch/x86/include/asm/thread_info.h
}}中),这些宏分别引用初始线程(启动内核的线程)及其堆栈。
据我所知,union thread_union
类型除了初始堆栈和线程信息外没有其他用途。此外,init_thread_info
部分仅在引导过程中需要,后续不再需要。
这意味着,如果使用结构体代替联合体,则struct thread_info
部分将在内存中保持未使用状态,只要内核正在运行即可。当然,这并不是很多字节... 但是,使用联合体 - 请记住,在Linux中,堆栈向下增长 - 初始线程信息位于初始堆栈区域的末尾,如果在内核代码内存在足够深的调用链,需要使用所有可用的内核堆栈位,那么初始thread_info将被堆栈数据覆盖。这没关系,因为它不再需要。
init_stack
时会溢出到init_thread_info
成员,覆盖它。假设,如我在括号中所注明的那样,宏被调整为指向联合体的开头。如果未调整宏,则初始线程信息将保留在内存中,未使用,直到重新启动或关闭。)init_thread_info
和init_stack
宏变得不必要地复杂,浪费其他/未来开发人员的时间,尝试解释原始意图。
最后,请记住,内核开发人员对实际结果比理论或标准更感兴趣。例如,C编译器的编写者可能会指出,根据C标准,访问联合中与上次分配给该联合使用的成员不同的成员将产生未定义的结果。但这并不重要:内核依赖于实际的、真实世界的行为,而不是任何标准的文本。这也意味着阅读代码、注释以及与内核相关的LKML或其他邮件列表上的讨论总是比依靠一般的C知识更加有启发性和可靠。
union thread_union
仅在引导期间用于初始内核线程是正确的。据我所知,每个进程都会有一个 union thread_union
。 - lord.garbage
thread_info
和stack
不需要同时存在。 - Lee Duhem