c - union 在 Linux 进程描述符中的用法

标签 c linux process linux-kernel unions

在阅读“Understanding Linux Kernel”时,我发现 union 被用于 Process Descriptor 数据结构。

union thread_union {
   struct thread_info thread_info;
   unsigned long stack[2048]; /* 1024 for 4KB stacks */
};

当两个数据结构都被使用时,为什么在这里使用 union for 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 在很多地方使用(在内核源代码中使用了数百次),并且在不同的体系结构之间有所不同。

OP 想知道为什么不改用结构:

struct thread_struct {
    struct thread_info thread_info;
    unsigned long stack[(THREAD_SIZE - sizeof (struct thread_info))/sizeof (long)];
};

(我假设相关宏 init_thread_infoinit_stack 进行了相应调整,即两者都引用 init_thread_union 的开始,这样实际的内存布局就不会改变。)

原因很简单, union 体的两个成员打算驻留在同一个内存区域,因此 union 体更合适。

完整的推理更加复杂。要点是所有架构都在init/init_task.c 中定义了一个这种 union 类型的init_thread_union 变量。 , 用于启动时的初始内核线程和预处理器宏

#define init_thread_info    (init_thread_union.thread_info)
#define init_stack          (init_thread_union.stack)

在特定于体系结构的头文件中(例如,在 x86 上的 arch/x86/include/asm/thread_info.h 中)。这些宏分别引用初始线程(启动内核的线程)及其堆栈。

据我所知,union thread_union 类型除了初始堆栈和线程信息外没有用于任何其他目的。此外,init_thread_info 部分仅在启动期间需要,之后不需要。

这意味着如果使用结构而不是 union ,只要内核在运行,struct thread_info 部分将在内存中保持未使用状态。当然,它不是很多字节。但是,使用 union ——记住在 Linux 中,堆栈会向下增长——初始线程信息位于初始堆栈区域的末尾,如果在某个时候有一个很深的如果内核代码中有足够的调用链需要每一位可用的内核堆栈,则初始的 thread_info 将被堆栈数据覆盖。没关系,因为不再需要它。

(如果你很敏锐,你会发现使用这个结构会产生同样的实际效果:用完init_stack会溢出到init_thread_info成员,覆盖它。假设,正如我在括号中指出的那样,宏被调整为指向 union 的开始。如果宏没有被调整,那么初始线程信息将保留在内存中,未被使用,直到重新启动或关闭。 )

所以,总而言之,union 更合适,因为内核开发人员将 union 类型专门用于初始线程信息和初始堆栈(用于启动内核的线程),并且明确希望它们占用相同的内存区域。尽管使用结构可以实现完全相同的实际效果,但它会使 init_thread_infoinit_stack 宏不必要地复杂化,浪费其他/ future 开发人员的时间来破译初衷。

最后,请记住,内核开发人员对实际结果比对理论或标准更感兴趣。例如,C 编译器编写者可能会指出,根据 C 标准,访问与上次对 union 赋值时不同的 union 成员会产生未定义的结果。这无关紧要:内核取决于实际的、现实世界的行为,而不是任何标准的文本。这也意味着阅读关于 LKML 的代码、评论和讨论。或其他与内核相关的邮件列表,总是比依赖一般的 C 知识更具指导性和可靠性。

关于c - union 在 Linux 进程描述符中的用法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22140075/

相关文章:

c - 通过套接字传递字符串数组

c - 查找封闭的不规则三角3D曲面与笛卡尔矩形3D网格的交点

linux - 避免在 bash 命令中使用临时文件

windows - 如何以编程方式在 Windows 10 的特定监视器上启动应用程序?

ubuntu - 使用 gnuplot 绘制进程树

c - 从 C 函数返回数组

无法从链表中删除最后一个元素

linux - 为什么我的 shellcode 在从 C 执行时会出现段错误,而不是作为独立的可执行文件执行?

linux - 使用 bash 脚本在文件中显示 Linux 中所有正在运行的进程的名称

c - 使用进程来计算文件数量