]> Cypherpunks repositories - gostls13.git/commit
[release-branch.go1.23] runtime: update and restore g0 stack bounds at cgocallback
authorCherry Mui <cherryyz@google.com>
Mon, 22 Jul 2024 20:23:43 +0000 (16:23 -0400)
committerCarlos Amedee <carlos@golang.org>
Fri, 13 Dec 2024 19:18:11 +0000 (11:18 -0800)
commit59b7d40774b29bd1da1aa624f13233111aff4ad2
tree62a9991f977e639a5aa6422d1f7e0d921b829efa
parent69c8cfe29bb677614c01f8dae3901d6954411af8
[release-branch.go1.23] runtime: update and restore g0 stack bounds at cgocallback

Currently, at a cgo callback where there is already a Go frame on
the stack (i.e. C->Go->C->Go), we require that at the inner Go
callback the SP is within the g0's stack bounds set by a previous
callback. This is to prevent that the C code switches stack while
having a Go frame on the stack, which we don't really support. But
this could also happen when we cannot get accurate stack bounds,
e.g. when pthread_getattr_np is not available. Since the stack
bounds are just estimates based on the current SP, if there are
multiple C->Go callbacks with various stack depth, it is possible
that the SP of a later callback falls out of a previous call's
estimate. This leads to runtime throw in a seemingly reasonable
program.

This CL changes it to save the old g0 stack bounds at cgocallback,
update the bounds, and restore the old bounds at return. So each
callback will get its own stack bounds based on the current SP,
and when it returns, the outer callback has the its old stack
bounds restored.

Also, at a cgo callback when there is no Go frame on the stack,
we currently always get new stack bounds. We do this because if
we can only get estimated bounds based on the SP, and the stack
depth varies a lot between two C->Go calls, the previous
estimates may be off and we fall out or nearly fall out of the
previous bounds. But this causes a performance problem: the
pthread API to get accurate stack bounds (pthread_getattr_np) is
very slow when called on the main thread. Getting the stack bounds
every time significantly slows down repeated C->Go calls on the
main thread.

This CL fixes it by "caching" the stack bounds if they are
accurate. I.e. at the second time Go calls into C, if the previous
stack bounds are accurate, and the current SP is in bounds, we can
be sure it is the same stack and we don't need to update the bounds.
This avoids the repeated calls to pthread_getattr_np. If we cannot
get the accurate bounds, we continue to update the stack bounds
based on the SP, and that operation is very cheap.

On a Linux/AMD64 machine with glibc:

name                     old time/op  new time/op  delta
CgoCallbackMainThread-8  96.4µs ± 3%   0.1µs ± 2%  -99.92%  (p=0.000 n=10+9)

Updates #68285.
Updates #68587.
Fixes #69988.

Change-Id: I3422badd5ad8ff63e1a733152d05fb7a44d5d435
Reviewed-on: https://go-review.googlesource.com/c/go/+/600296
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
(cherry picked from commit 76a8409eb81eda553363783dcdd9d6224368ae0e)
Reviewed-on: https://go-review.googlesource.com/c/go/+/635775
src/cmd/cgo/internal/testcarchive/carchive_test.go
src/cmd/cgo/internal/testcarchive/testdata/libgo10/a.go [new file with mode: 0644]
src/cmd/cgo/internal/testcarchive/testdata/libgo9/a.go
src/cmd/cgo/internal/testcarchive/testdata/main10.c [new file with mode: 0644]
src/cmd/cgo/internal/testcarchive/testdata/main9.c
src/runtime/cgo/gcc_stack_unix.c
src/runtime/cgocall.go
src/runtime/proc.go
src/runtime/runtime2.go