查看“Thread Local Storage”的源代码
←
Thread Local Storage
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
线程本地存储(Thread Local Storage - TLS)是针对每个线程的全局变量。 像[[GCC]]这样的编译器提供了一个<tt>__thread</tt>关键字来按照线程标记全局变量。 这一特性需要程序加载器和线程创建者的支持。 <source lang="c"> __thread int errno; int get_errno() { return errno; } </source> [[x86-64]]和[[System V ABI]]编译器会将此代码编译成如下汇编程序集: <pre> .globl errno .section .tbss,"awT",@nobits .align 4 .type errno, @object .size errno, 4 errno: .zero 4 ... movl %fs:errno@tpoff, %eax </pre> <tt>errno</tt>全局变量被放入一个特殊的线程本地bss节(.tbss)(如果已初始化时是.tdata),特殊的操作在程序链接时和程序加载间发生。 创建线程时,会进行per-thread allocation(包含线程本地存储、用户空间线程结构以及其他内容)。 每个线程变量都位于该分配内存中的固定偏移量处。 在上面的示例中,%fs段从线程的用户空间线程结构(%fs因此用作额外寄存器)开始, 同时特别的<tt>errno@tpoff</tt>链接器符号是从线程的用户空间线程结构到每线程errno值的偏移量。 ==设计== ===主线程本地存储副本(Master Thread Local Storage Copy)=== 该程序包含其线程本地存储(在编译时初始化)的主副本,该主副本在创建线程时使用。 此特殊段由链接器从<tt>创建。tdata</tt>(初始化的tls)和<tt>。tbss(零初始化tls)部分。 您可以通过在[[ELF]]程序头中搜索类型为<tt>PT_TLS</tt>(十进制值7)(与正常的<tt>PT_加载相反)的段来找到它。 线程本地存储主段的虚拟地址没有意义,因为它不是在特定的位置加载的,而是由您决定加载它的位置。 请注意,该段与普通段一样具有对齐约束(但链接器为您放置了这些约束)。 除了自己决定加载段的位置外,还可以像加载普通段一样加载该段。 === Per-thread allocation === 每个线程都有与其关联的内存分配。 它包含用户空间线程结构、线程本地存储,以及可能的其他内容。 每个线程都有一个线程自指针寄存器,该寄存器指向线程的用户空间线程结构,用于快速确定当前线程,并提供对线程本地存储的快速访问。 每个线程的确切语义取决于体系结构及其ABI,以及可执行文件是静态链接还是动态链接。 用户空间线程结构的布局部分由ABI授权。 在某些平台(i386和x86-64)上,它的开头必须有一个指向自身的指针。 除了这些必需的部分之外,结构的其余部分由您决定,它对于许多事情都很有用,比如记住线程终止时必须释放的分配。 线程本地存储位于用户空间线程结构的固定偏移处,因此线程本地存储中的每个变量也位于固定偏移处。 该偏移量在链路时确定,使用特殊的<tt>foo@tpoff</tt>链接器符号。 定位特定的线程局部变量就像获取线程自指针并添加固定偏移量一样简单。 == ABI == 这里是[[System V ABI]]中实际细节的摘要。 === i386 === 线程自指针寄存器是%gs段的基地址。 它被设置为当前线程的用户空间线程结构的地址。 在当前CPU上切换线程时,更改该CPU[[GDT]]的gs段的基址,并重新加载gs寄存器。 指向用户空间线程结构本身的指针是用户空间线程结构的第一个成员。 线程本地存储(在将其大小四舍五入到对齐状态后)位于用户空间线程结构之前。 偏移量为负。 要放置用户空间线程结构和线程本地存储,请执行以下操作: <source lang="c"> size_t allocation_alignment = max(master_tls_alignment, alignof(struct uthread)); size_t allocation_size = alignup(master_tls_size, allocation_alignment) + sizeof(struct uthread); unsigned char* allocation = allocate(allocation_size, allocation_alignment); struct uthread* uthread = allocation + alignup(master_tls_size, allocation_alignment); unsigned char* tls = ((unsigned char*) uthread) - alignup(master_tls_size, master_tls_alignment); </source> 请注意,如果线程本地结构的对齐方式小于struct uthread,那么它可能不在per-thread allocation的开头。 线程本地存储和用户空间线程结构正确对齐是至关重要的。 然后初始化用户空间线程结构的自指针和线程本地存储: <source lang="c"> uthread->self_pointer = uthread; memcpy(tls, master_tls, master_tls_size); </source> === x86-64 === 线程自指针寄存器是%fs段的基地址。 它被设置为当前线程的用户空间线程结构的地址。 切换线程时,设置FSBASE[[MSR]](0xC0000100)。 指向用户空间线程结构本身的指针是用户空间线程结构的第一个成员。 per-thread allocation按照[[#i386]]章节中的描述进行安排和放置。 ===其他=== 参见<tt>tls。pdf</tt>请在下面的文档中记录,然后请在此处记录详细信息: ==实现== 加载程序后,内核应引导主线程的线程本地存储: # 在程序加载期间,在程序头中找到线程本地存储段,并将其加载到某个地方。 # 为主线程创建per-thread allocation。 # 将主线程本地存储复制到主线程的线程本地存储。 # 在主线程的用户空间线程结构中,存储: 每个线程分配的位置/大小、主线程本地存储位置/大小/对齐、主线程的线程本地存储位置/大小、主线程的堆栈位置/大小,等等。 这允许线程生成新线程,并在其自身之后进行清理。 #将主线程的线程自指针寄存器设置为主线程的用户空间线程结构。 这种方法允许在加载程序时立即运行线程本地存储,并使创建新线程变得简单。 为新线程设置线程本地存储很简单: # 为新线程创建per-thread allocation。 # 将主线程本地存储复制到新线程的线程本地存储。 # 初始化新线程的用户空间线程结构。 # 将新线程的线程自指针寄存器设置为新线程的用户空间线程结构。 有些Unix内核(如Linux)实际上没有为主线程设置线程本地存储。 libc需要解析程序的ELF可执行文件,以定位和加载主线程本地存储副本本身,并引导主线程。 This has the obvious disadvantages of having early times where language features doesn't work and that every executable gets linked in an ELF loader (in case it uses thread local storage). ==另见== ===标准=== * [http://www.akkadia.org/drepper/tls.pdf ELF Handling For Thread-Local Storage] ===文章=== * [[ELF]] * [[GDT]] * [[MSR]] * [[System V ABI]] === 论坛主题=== * [http://forum.osdev.org/viewtopic.php?f=15&t=28339 Minimal Static Link] - [[User:Sortie|sortie]] posts about reducing startup libc bloat such as thread local storage initialization by moving it into the kernel to much success. === IRC === * [http://bespin.org/~qz/search/?view=1&c=osdev&y=14&m=11&d=17 #osdev 2014-11-17] - <tt>sortie</tt> and <tt>maxdev</tt> have a conversation about thread local storage. ===实现=== * [[User:Sortie/Sortix_Thread_Local_Storage|Sortix Thread Local Storage Implementation]] - Notes on [[User:Sortie|sortie]]'s implementation. [[Category:ABI]] [[Category:C]] [[Category:Processes and Threads]]
返回至“
Thread Local Storage
”。
导航菜单
个人工具
登录
命名空间
页面
讨论
变体
已展开
已折叠
查看
阅读
查看源代码
查看历史
更多
已展开
已折叠
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
工具
链入页面
相关更改
特殊页面
页面信息