go 运行时:在darwin/arm和darwin/arm64上使用寄存器代替TLS来存储G指针,

zfycwa2u  于 5个月前  发布在  Go
关注(0)|答案(9)|浏览(72)

需要决定如何在darwin/arm上处理TLS。在x86上,TLS从pthread_get/setspecific实现中移除,被苹果保留在一个TLS的专用槽位(参见#23617)。这对于arm/arm64来说是不可能的,所以我们仍然使用旧的方法。由于这些架构有更多的寄存器,我们可能应该只为G指针预留一个寄存器。
预留一个寄存器可能会使一些现有的汇编代码失效。这是一个计划中的障碍,需要调查它可能有多糟糕。
也许有人可以想到一个更好的解决方案。
在能够为arm执行#17490之前,我们可能需要一个解决方案。

mrfwxfqh

mrfwxfqh1#

我认为,我们已经在ARM和ARM64上预留了一个G寄存器,无论操作系统是什么。这是ARM上的R10,以及ARM64上的R28。TLS只在跨越Go-C边界时使用,当我们调用C时,将G寄存器保存到TLS槽中,并在进入Go代码时重新加载它,因为C代码可能会破坏我们的G寄存器。

7eumitmz

7eumitmz2#

也许这就没有必要了。

rggaifut

rggaifut3#

pthread_get/set的魔法仍然存在于runtime/cgo/gcc_darwin_arm*.c中,所以我不认为这是不必要的。
@cherrymui鉴于我们只使用TLS槽位进行Cgo,我们是否可以使用一个callee-saved寄存器来存储G,从而避免使用TLS槽位(以及保存/恢复)?

gk7wooem

gk7wooem4#

我没有详细研究过代码,但我不确定callee-saved寄存器是否足够。C代码仍然可以暂时使用该寄存器,并且信号可能在这一点发生。信号处理器runtime.sigtramp需要查看G寄存器来判断我们所在的Go堆栈是哪一个。

ogq8wdun

ogq8wdun5#

回溯一级:为什么在C调用中,runtime.sigtramp需要知道正在运行的goroutine?

jm81lzqq

jm81lzqq6#

我不确定我完全理解这个问题,但是在运行时/ sys_darwin_arm.s 和运行时/ sys_darwin_arm64.s 中看到了 sigtramp 代码。它今天检查了 g 寄存器,该寄存器从 TLS 槽加载出来。

mfpqipee

mfpqipee7#

除了信号处理器,另一个需要G的地方是Go调用C,然后C回调给Go。我认为我们希望使用相同的G。

wyyhbhjk

wyyhbhjk8#

这个状态是什么?这里是否真的存在错误?

bvhaajcl

bvhaajcl9#

#17490 是一个固定值,即使在 iOS 上也是如此,因此剩下的 bug 是,我们依赖于一个未记录的假设,即由 pthread_key_create 分配的 TLS 插槽位于 TLS 基址的某个正偏移量处。请参阅
go/src/runtime/cgo/gcc_darwin_arm64.c
第31行至第45行 59ea685
| | err=pthread_key_create(&k, nil); |
| | if(err!=0) { |
| | fprintf(stderr, "runtime/cgo: pthread_key_create failed: %d
", err); |
| | abort(); |
| | } |
| | //fprintf(stderr, "runtime/cgo: k = %d, tlsbase = %p
", (int)k, tlsbase); // debug |
| | pthread_setspecific(k, (void*)magic); |
| | // The first key should be at 257. |
| | for (i=0; i<PTHREAD_KEYS_MAX; i++) { |
| | if ((tlsbase+i) == (void)magic) { |
| | tlsg= (void)(isizeof(void)); |
| | pthread_setspecific(k, 0); |
| | return; |
| | } |
| | } |
我们最近不得不删除一个类似的 Android( #29674 )假设。由于我们在 arm 和 arm64 上使用寄存器 g,因此解决此问题的最佳方法可能是在进入或退出 C 代码时调用 pthread_getspecific 和 pthread_setspecific。

相关问题