Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runtime: SIGPROF incompatibility with PHP SIGPROF-based timeout functionality #56260

Open
dunglas opened this issue Oct 16, 2022 · 2 comments
Open
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@dunglas
Copy link
Contributor

dunglas commented Oct 16, 2022

What version of Go are you using (go version)?

$ go version
go version go1.19.2 darwin/arm64

Does this issue reproduce with the latest release?

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/dunglas/Library/Caches/go-build"
GOENV="/Users/dunglas/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/dunglas/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/dunglas/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/opt/homebrew/Cellar/go/1.19.2/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/opt/homebrew/Cellar/go/1.19.2/libexec/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.19.2"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/1v/jy3dpwd91071b3mx48myh6q80000gn/T/go-build15656582=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

I'm working on a library that embeds the PHP interpreter in Go programs.

PHP is using SIGPROF for its max_execution_time and max_input_time features.
When PHP receives a SIGPROF signal, it stops the current script with a PHP error.

The problem is that Go also sends SIGPROF signals for its own profiling features (running the test suite is enough to trigger these signals) and these signals are propagated to the threads started and managed by (Franken)PHP.

It may be a Mac-specific issue, as I'm not able to the problem on Linux.

To reproduce the issue, you can follow these instructions but without setting the -DNO_SIGPROF flag when compiling PHP then run the test suite (go test -v).

Patching PHP to use SIGALARM instead of SIGPROF also fixes the issue, but doesn't look like a very good option: php/php-src#9738

What did you expect to see?

No SIGPROF signal is delivered to the C signal handler or at least a way to detect that it comes from Go.

What did you see instead?

SIGPROF is handled by PHP, and the script stops with an error.

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Oct 16, 2022
@prattmic
Copy link
Member

prattmic commented Oct 17, 2022

If I understand https://github.com/php/php-src/blob/5a68d991ad20402ebfecba2a30b2dfdb197c8c8e/Zend/zend_execute_API.c#L1429 correctly, PHP is using setitimer(ITIMER_PROF) as a CPU time limit, and the problem that you are running into is that it thinks the timeout has been reached when it receives a spurious SIGPROF?

For that specific issue, it seems like the best approach would be for PHP to allow for spurious signals. e.g., when setting up the timeout, use clock_gettime(CLOCK_PROCESS_CPUTIME_ID) to get the current CPU time, and then the signal handle uses clock_gettime(CLOCK_PROCESS_CPUTIME_ID) to compute the duration to determine if the timeout has been reached.

However, there are more issues. e.g., both Go and PHP are trying to use the single setitimer(ITIMER_PROF) timer for different purposes. To work together they would probably need to find the lowest common denominator period between the two uses and then ignore extra signals beyond the frequency they care about. On Linux, Go and/or PHP could use timer_create() to create custom CPU timers that won't conflict with each other (they'd still need to filter signals by timer source), but I don't think all OSes have equivalent functionality. On Darwin/macOS, I think setitimer may be the only available CPU timer?

@prattmic prattmic added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Oct 17, 2022
@prattmic prattmic added this to the Backlog milestone Oct 17, 2022
@ianlancetaylor
Copy link
Contributor

ianlancetaylor commented Oct 17, 2022

For better or for worse, there is only one SIGPROF signal. There is really no way that both PHP and Go can use it simultaneously for different purposes.

That said, simply running a plain go test should not cause Go to start generating SIGPROF signals. That should only happen if something explicitly calls runtime/pprof.StartCPUProfile. So the first step might be to find out what is calling that function. An ordinary Go test should only do that if explicitly invoked with the -test.cpuprofile option.

@prattmic prattmic changed the title runtime: SIGPROF triggers non-Go signal handlers (cgo) runtime: SIGPROF incompatibility with PHP SIGPROF-based timeout functionality Oct 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
Status: Todo
Development

No branches or pull requests

4 participants