Glibc 2.35中的可重启序列

2022-02-13 01:44:57

实际上,运行临界区是将rseq_cs结构的地址存储到注册到内核的rseq结构中;这应该在进入本节之前完成。每当内核抢占线程时,它都会检查指令指针,以查看criticalsection当时是否正在执行;如果是这样,当线程恢复执行时,它将跳转到abort_ip地址,此时它应该恢复并重试。可重启序列ABI的一个潜在问题是,任何giventhread都只能在内核中注册一个rseq结构。即使只检查一个结构,也会给调度器的HotTestPart增加一点开销;检查他们的名单是不可接受的。这种限制是有道理的,但在一个线程中可能有多个可重启序列的用户的情况下,它确实会带来问题;其中一些可能隐藏在库中,对这些库的用户是不可见的,可能是调用堆栈上的几层。要使可重启序列成为一种可靠的机制,必须有一种方法来防止这些用户相互踩踏#39;脚趾。如果glibc要向用户公开可重启序列,它必须对共享问题有一个可能的答案。Florian Weimer的实现采用了将glibc置于该机制用户中间的方法。因此,在初始化期间,rseq结构与rseq()系统调用的注册由Glibc自己完成;当用户代码运行时,该设置将已经执行。如果应用程序想要执行自己的注册(并且根本不使用glibc支持),glib。pthread。rseq Tunable可用于禁用自动注册。通过glibc使用可重启序列的应用程序应包括<;sys/rseq。h>;。该标题定义了rseq和rseq_cs结构以及几个重要变量,其中第一个变量是_rseq_size。这将是图书馆注册的rseqstructure的大小,如果没有注册,则为零';无论出于何种原因(例如,内核不支持或已禁用)。找到glibc注册的rseq结构并不像人们想象的那样是一个很难解决的问题。它存储在由库维护的线程控制块(TCB)中;具体来说,它可以在线程指针的_rseq_偏移字节的偏移量处找到。然而,实际上,获取线程指针是一件特定于体系结构的事情;GCC为某些体系结构提供了_内置_线程_指针(),但并非所有体系结构都提供了。碰巧的是,x86是一个例外;线程指针存储在FS寄存器中,应用程序必须自己获取它。glibc注册的rseq结构由给定线程中的所有用户共享,但每个用户都应该创建自己的rseq_csstructure来描述其关键部分。在进入临界区之前,线程应该将其rseq_cs结构的地址存储到全局rseq结构的rseq_cs字段中;它应该将该字段重置为NULL onexit。这种设置意味着关键部分不能嵌套,但这些部分应该很短,无论如何都不应该调用其他代码,所以这不会是一个问题。位于abort_ip的代码必须以特殊的RSEQ_SIG sentinel开头,该sentinel由架构依赖者定义。请注意,如果调用了中止代码,内核会将rseq_csfield归零,并且必须在重新进入临界段之前重新分配。还有一个_rseq_flags变量,包含注册内核时使用的标志;据魏默';sdocumentation补丁,目前该变量始终设置为零。有了这种结构,使用glibc的应用程序现在可以以协作的方式使用用户可设置的序列。不幸的是,没有';任何使用这个新API的有用代码示例;这在这一点上是全新的东西。正如读者现在可能已经理解的那样,实际上编写criticalsection几乎肯定需要使用汇编语言。这显然不是一个用于临时或频繁使用的功能,但在具有高可扩展性需求的系统中,它显然可以显著提高性能。GNU C库中的支持将使可重启序列更容易访问,但它似乎注定会成为少数开发人员使用的小众功能。(登录发表评论)