-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
x/playground,internal/poll: timeout or long run time when using httptest.NewServer #60356
Comments
This is definitely related to the |
Change https://go.dev/cl/497618 mentions this issue: |
Change https://go.dev/cl/497619 mentions this issue: |
I couldn't help but investigate a bit, and got as far as writing a proof-of-concept regression test. 😅 I don't plan to work on this further, but if someone wants to take it from here they're welcome to build on my WIP CLs. |
(@ianlancetaylor, this seems to be an interaction between the runtime and poller when built with |
If I build the test case with I don't understand this line in if !iscgo && cgoHasExtraM && extraMLength.Load() > 0 { Why is it testing run := mcount() - sched.nmidle - sched.nmidlelocked - sched.nmsys - int32(extraMLength.Load())
if run > 0 {
return
} That is, account for all of CC @golang/runtime |
We can't simply write that because then this program fails checkdead and claims to be deadlocked: // Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !plan9 && !windows
// +build !plan9,!windows
package main
/*
#include <unistd.h>
#include <pthread.h>
void go_callback();
static void *thr(void *arg) {
sleep(1);
go_callback();
return 0;
}
static void foo() {
pthread_t th;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 256 << 10);
pthread_create(&th, &attr, thr, 0);
//pthread_join(th, 0);
}
*/
import "C"
import (
"os"
)
//export go_callback
func go_callback() {
os.Exit(0)
}
func main() {
C.foo()
select {}
} That is, we use extraMLength > 0 as an indication that we might get a callback from C, though admittedly this might not be the best way to represent this. I haven't actually looked at the faketime issue yet, that's next. |
Oh, right, I forgot about the possibility of a callback. I think that means that faketime fundamentally can't work with a program that uses cgo. We never know for sure when to advance the fake clock. |
Hm, actually I don't see a clean way to resolve this. Package net calls into C, meaning it is now technically possible for C to callback into Go at any time in the future. So it is not ever safe to say that there is truly nothing to do except move faketime forward. A couple of possibilities:
|
I think we should do that. If there are no Go threads running, and no Go threads blocked in syscalls, and some timer waiting in the timer heap, then we should advance The vast majority of Playground programs won't have asynchronous callbacks from C. (At best, they might have synchronous callbacks, but those shouldn't matter for (That is: |
The playground link in the issue summary usually times out, but on rare occasion deadlocks. By comparison the following program appears to deadlock in the playground very reliably for me on all Go versions in the playground (though on rare occasions it seems to succeed): https://go.dev/play/p/vRc-ulRCihw output for deadlock
expected output
I don't believe I'm contributing anything particularly novel here, but until I found this issue I thought this was completely reproducible. It wasn't until I saw the same deadlock with the playground link in the summary that I realized it's just very frequent. Given that a deadlock seems more severe than an I/O timeout, I figured I'd share another datapoint. (aside: I am pretty sure I have written the same, or nearly the same, playground program before, much more recently than 1.14, and never encountered this, so I wonder if another change has exacerbated it.) |
What version of Go are you using (
go version
)?go1.20 as reported by the playground.
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?N/A
What did you do?
https://go.dev/play/p/Pc_vys_LNVG
What did you expect to see?
It should run and terminate very quickly.
What did you see instead?
The same code (or very similar, modulo playground result caching) sometimes terminates immediately,
and sometimes prints:
When instrumented to print the goroutine stack traces on timeout, we see this set of stacks:
The program to produce that output is here: https://go.dev/play/p/7t5iObMhESj
Note the sleep just before the
request sent
is printed. Without that, the goroutine stack trace is aborted half way: it seems that the fact that the goroutine woke up triggered the runtime to run the other goroutines which should have been running anyway.The text was updated successfully, but these errors were encountered: