【问题标题】:usage of union in Linux process descriptorLinux进程描述符中联合的使用
【发布时间】:2014-03-03 06:27:52
【问题描述】:

在阅读“Understanding Linux Kernel”时,我发现联合正在用于进程描述符数据结构。

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

当这两种数据结构都被使用时,为什么在这里使用 union union thread_union

【问题讨论】:

  • 这里使用联合可能是因为thread_infostack不是同时需要的。
  • 或者数据大小需要是某种页面大小的倍数,并且结构位于堆栈顶部。我认为这是一个填充技巧。
  • @leeduhem 即使我在猜测。但不确定我们怀疑的need

标签: c linux process linux-kernel unions


【解决方案1】:

首先是

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 的开头,因此实际内存布局不会改变。)

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

完整的推理更复杂。重点是所有架构都在init/init_task.c中定义了这个联合类型的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 部分仅在启动期间需要,以后不需要。

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

(如果您非常敏锐,您会意识到使用该结构将具有相同的实际效果:用完 init_stack 会溢出到 init_thread_info 成员中,覆盖它。假设,正如我在括号,宏被调整为指向联合的开始。如果没有调整宏,那么初始线程信息将保留在内存中,未使用,直到重新启动或关闭。)

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

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

【讨论】:

  • 您认为初学者应该如何从内核源代码开始。我认为从这本书开始很好。
  • @neeru:我认为kernelnewbies.org,尤其是Kernel Hacking 部分,是一个很好的起点。就个人而言,我学到的关于内核的一切都是因为我有一些特定的东西需要修复、修改、扩展或理解。我强烈建议您从一些您觉得特别有趣的驱动程序或功能开始。如果没有您感兴趣的驱动程序或子系统,请查看Kernel Janitors 项目。潜心研究,尽你所能发挥作用。每个人都有空间。
  • 我不确定您关于union thread_union 仅用于启动期间的初始内核线程的说法是否属实。 Afaik 每个进程都会有一个union thread_union
猜你喜欢
  • 2018-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-28
  • 2018-11-29
  • 2011-04-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多