@@ -179,7 +179,7 @@ type Invocation struct {
179
179
CleanEnv bool
180
180
Env []string
181
181
WorkingDir string
182
- Logf func (format string , args ... interface {} )
182
+ Logf func (format string , args ... any )
183
183
}
184
184
185
185
// Postcondition: both error results have same nilness.
@@ -388,7 +388,9 @@ func runCmdContext(ctx context.Context, cmd *exec.Cmd) (err error) {
388
388
case err := <- resChan :
389
389
return err
390
390
case <- timer .C :
391
- HandleHangingGoCommand (startTime , cmd )
391
+ // HandleHangingGoCommand terminates this process.
392
+ // Pass off resChan in case we can collect the command error.
393
+ handleHangingGoCommand (startTime , cmd , resChan )
392
394
case <- ctx .Done ():
393
395
}
394
396
} else {
@@ -413,32 +415,32 @@ func runCmdContext(ctx context.Context, cmd *exec.Cmd) (err error) {
413
415
}
414
416
415
417
// Didn't shut down in response to interrupt. Kill it hard.
416
- // TODO(rfindley): per advice from bcmills@, it may be better to send SIGQUIT
417
- // on certain platforms, such as unix.
418
418
if err := cmd .Process .Kill (); err != nil && ! errors .Is (err , os .ErrProcessDone ) && debug {
419
419
log .Printf ("error killing the Go command: %v" , err )
420
420
}
421
421
422
422
return <- resChan
423
423
}
424
424
425
- func HandleHangingGoCommand (start time.Time , cmd * exec.Cmd ) {
425
+ // handleHangingGoCommand outputs debugging information to help diagnose the
426
+ // cause of a hanging Go command, and then exits with log.Fatalf.
427
+ func handleHangingGoCommand (start time.Time , cmd * exec.Cmd , resChan chan error ) {
426
428
switch runtime .GOOS {
427
429
case "linux" , "darwin" , "freebsd" , "netbsd" :
428
430
fmt .Fprintln (os .Stderr , `DETECTED A HANGING GO COMMAND
429
431
430
- The gopls test runner has detected a hanging go command. In order to debug
431
- this, the output of ps and lsof/fstat is printed below.
432
+ The gopls test runner has detected a hanging go command. In order to debug
433
+ this, the output of ps and lsof/fstat is printed below.
432
434
433
- See golang/go#54461 for more details.` )
435
+ See golang/go#54461 for more details.` )
434
436
435
437
fmt .Fprintln (os .Stderr , "\n ps axo ppid,pid,command:" )
436
438
fmt .Fprintln (os .Stderr , "-------------------------" )
437
439
psCmd := exec .Command ("ps" , "axo" , "ppid,pid,command" )
438
440
psCmd .Stdout = os .Stderr
439
441
psCmd .Stderr = os .Stderr
440
442
if err := psCmd .Run (); err != nil {
441
- panic ( fmt . Sprintf ( " running ps: %v" , err ) )
443
+ log . Printf ( "Handling hanging Go command: running ps: %v" , err )
442
444
}
443
445
444
446
listFiles := "lsof"
@@ -452,10 +454,24 @@ See golang/go#54461 for more details.`)
452
454
listFilesCmd .Stdout = os .Stderr
453
455
listFilesCmd .Stderr = os .Stderr
454
456
if err := listFilesCmd .Run (); err != nil {
455
- panic (fmt .Sprintf ("running %s: %v" , listFiles , err ))
457
+ log .Printf ("Handling hanging Go command: running %s: %v" , listFiles , err )
458
+ }
459
+ // Try to extract information about the slow go process by issuing a SIGQUIT.
460
+ if err := cmd .Process .Signal (sigStuckProcess ); err == nil {
461
+ select {
462
+ case err := <- resChan :
463
+ stderr := "not a bytes.Buffer"
464
+ if buf , _ := cmd .Stderr .(* bytes.Buffer ); buf != nil {
465
+ stderr = buf .String ()
466
+ }
467
+ log .Printf ("Quit hanging go command:\n \t err:%v\n \t stderr:\n %v\n \n " , err , stderr )
468
+ case <- time .After (5 * time .Second ):
469
+ }
470
+ } else {
471
+ log .Printf ("Sending signal %d to hanging go command: %v" , sigStuckProcess , err )
456
472
}
457
473
}
458
- panic ( fmt . Sprintf ("detected hanging go command (golang/go#54461); waited %s\n \t command:%s\n \t pid:%d" , time .Since (start ), cmd , cmd .Process .Pid ) )
474
+ log . Fatalf ("detected hanging go command (golang/go#54461); waited %s\n \t command:%s\n \t pid:%d" , time .Since (start ), cmd , cmd .Process .Pid )
459
475
}
460
476
461
477
func cmdDebugStr (cmd * exec.Cmd ) string {
0 commit comments