mirror of
git://gcc.gnu.org/git/gcc.git
synced 2024-11-24 12:54:02 +08:00
8dc2499aa6
gotools/ * Makefile.am (go_cmd_cgo_files): Add ast_go118.go (check-go-tool): Copy golang.org/x/tools directories. * Makefile.in: Regenerate. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/384695
350 lines
7.1 KiB
Go
350 lines
7.1 KiB
Go
// 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 aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
|
|
|
|
package syscall_test
|
|
|
|
import (
|
|
"internal/testenv"
|
|
"io"
|
|
"math/rand"
|
|
"os"
|
|
"os/exec"
|
|
"os/signal"
|
|
"runtime"
|
|
"syscall"
|
|
"testing"
|
|
"time"
|
|
"unsafe"
|
|
)
|
|
|
|
type command struct {
|
|
pipe io.WriteCloser
|
|
proc *exec.Cmd
|
|
test *testing.T
|
|
}
|
|
|
|
func (c *command) Info() (pid, pgrp int) {
|
|
pid = c.proc.Process.Pid
|
|
|
|
pgrp, err := syscall.Getpgid(pid)
|
|
if err != nil {
|
|
c.test.Fatal(err)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (c *command) Start() {
|
|
if err := c.proc.Start(); err != nil {
|
|
c.test.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func (c *command) Stop() {
|
|
c.pipe.Close()
|
|
if err := c.proc.Wait(); err != nil {
|
|
c.test.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func create(t *testing.T) *command {
|
|
testenv.MustHaveExec(t)
|
|
|
|
proc := exec.Command("cat")
|
|
stdin, err := proc.StdinPipe()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
return &command{stdin, proc, t}
|
|
}
|
|
|
|
func parent() (pid, pgrp int) {
|
|
return syscall.Getpid(), syscall.Getpgrp()
|
|
}
|
|
|
|
func TestZeroSysProcAttr(t *testing.T) {
|
|
ppid, ppgrp := parent()
|
|
|
|
cmd := create(t)
|
|
|
|
cmd.Start()
|
|
defer cmd.Stop()
|
|
|
|
cpid, cpgrp := cmd.Info()
|
|
|
|
if cpid == ppid {
|
|
t.Fatalf("Parent and child have the same process ID")
|
|
}
|
|
|
|
if cpgrp != ppgrp {
|
|
t.Fatalf("Child is not in parent's process group")
|
|
}
|
|
}
|
|
|
|
func TestSetpgid(t *testing.T) {
|
|
ppid, ppgrp := parent()
|
|
|
|
cmd := create(t)
|
|
|
|
cmd.proc.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
|
cmd.Start()
|
|
defer cmd.Stop()
|
|
|
|
cpid, cpgrp := cmd.Info()
|
|
|
|
if cpid == ppid {
|
|
t.Fatalf("Parent and child have the same process ID")
|
|
}
|
|
|
|
if cpgrp == ppgrp {
|
|
t.Fatalf("Parent and child are in the same process group")
|
|
}
|
|
|
|
if cpid != cpgrp {
|
|
t.Fatalf("Child's process group is not the child's process ID")
|
|
}
|
|
}
|
|
|
|
func TestPgid(t *testing.T) {
|
|
ppid, ppgrp := parent()
|
|
|
|
cmd1 := create(t)
|
|
|
|
cmd1.proc.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
|
cmd1.Start()
|
|
defer cmd1.Stop()
|
|
|
|
cpid1, cpgrp1 := cmd1.Info()
|
|
|
|
if cpid1 == ppid {
|
|
t.Fatalf("Parent and child 1 have the same process ID")
|
|
}
|
|
|
|
if cpgrp1 == ppgrp {
|
|
t.Fatalf("Parent and child 1 are in the same process group")
|
|
}
|
|
|
|
if cpid1 != cpgrp1 {
|
|
t.Fatalf("Child 1's process group is not its process ID")
|
|
}
|
|
|
|
cmd2 := create(t)
|
|
|
|
cmd2.proc.SysProcAttr = &syscall.SysProcAttr{
|
|
Setpgid: true,
|
|
Pgid: cpgrp1,
|
|
}
|
|
cmd2.Start()
|
|
defer cmd2.Stop()
|
|
|
|
cpid2, cpgrp2 := cmd2.Info()
|
|
|
|
if cpid2 == ppid {
|
|
t.Fatalf("Parent and child 2 have the same process ID")
|
|
}
|
|
|
|
if cpgrp2 == ppgrp {
|
|
t.Fatalf("Parent and child 2 are in the same process group")
|
|
}
|
|
|
|
if cpid2 == cpgrp2 {
|
|
t.Fatalf("Child 2's process group is its process ID")
|
|
}
|
|
|
|
if cpid1 == cpid2 {
|
|
t.Fatalf("Child 1 and 2 have the same process ID")
|
|
}
|
|
|
|
if cpgrp1 != cpgrp2 {
|
|
t.Fatalf("Child 1 and 2 are not in the same process group")
|
|
}
|
|
}
|
|
|
|
func TestForeground(t *testing.T) {
|
|
if runtime.GOOS == "hurd" {
|
|
t.Skip("skipping; TestForeground: fails on GNU/Hurd")
|
|
}
|
|
signal.Ignore(syscall.SIGTTIN, syscall.SIGTTOU)
|
|
defer signal.Reset()
|
|
|
|
tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
|
|
if err != nil {
|
|
t.Skipf("Can't test Foreground. Couldn't open /dev/tty: %s", err)
|
|
}
|
|
defer tty.Close()
|
|
|
|
fpgrp := syscall.Pid_t(0)
|
|
|
|
errno := syscall.Ioctl(tty.Fd(), syscall.TIOCGPGRP, unsafe.Pointer(&fpgrp))
|
|
if errno != 0 {
|
|
t.Fatalf("TIOCGPGRP failed with error code: %s", errno)
|
|
}
|
|
|
|
if fpgrp == 0 {
|
|
t.Fatalf("Foreground process group is zero")
|
|
}
|
|
|
|
ppid, ppgrp := parent()
|
|
|
|
cmd := create(t)
|
|
|
|
cmd.proc.SysProcAttr = &syscall.SysProcAttr{
|
|
Ctty: int(tty.Fd()),
|
|
Foreground: true,
|
|
}
|
|
cmd.Start()
|
|
|
|
cpid, cpgrp := cmd.Info()
|
|
|
|
if cpid == ppid {
|
|
t.Fatalf("Parent and child have the same process ID")
|
|
}
|
|
|
|
if cpgrp == ppgrp {
|
|
t.Fatalf("Parent and child are in the same process group")
|
|
}
|
|
|
|
if cpid != cpgrp {
|
|
t.Fatalf("Child's process group is not the child's process ID")
|
|
}
|
|
|
|
cmd.Stop()
|
|
|
|
// This call fails on darwin/arm64. The failure doesn't matter, though.
|
|
// This is just best effort.
|
|
syscall.Ioctl(tty.Fd(), syscall.TIOCSPGRP, unsafe.Pointer(&fpgrp))
|
|
}
|
|
|
|
func TestForegroundSignal(t *testing.T) {
|
|
tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
|
|
if err != nil {
|
|
t.Skipf("couldn't open /dev/tty: %s", err)
|
|
}
|
|
defer tty.Close()
|
|
|
|
// This should really be pid_t, however _C_int (aka int32) is generally
|
|
// equivalent.
|
|
fpgrp := int32(0)
|
|
|
|
errno := syscall.Ioctl(tty.Fd(), syscall.TIOCGPGRP, unsafe.Pointer(&fpgrp))
|
|
if errno != 0 {
|
|
t.Fatalf("TIOCGPGRP failed with error code: %s", errno)
|
|
}
|
|
|
|
if fpgrp == 0 {
|
|
t.Fatalf("Foreground process group is zero")
|
|
}
|
|
|
|
defer func() {
|
|
signal.Ignore(syscall.SIGTTIN, syscall.SIGTTOU)
|
|
syscall.Ioctl(tty.Fd(), syscall.TIOCSPGRP, unsafe.Pointer(&fpgrp))
|
|
signal.Reset()
|
|
}()
|
|
|
|
ch1 := make(chan os.Signal, 1)
|
|
ch2 := make(chan bool)
|
|
|
|
signal.Notify(ch1, syscall.SIGTTIN, syscall.SIGTTOU)
|
|
defer signal.Stop(ch1)
|
|
|
|
cmd := create(t)
|
|
|
|
go func() {
|
|
cmd.proc.SysProcAttr = &syscall.SysProcAttr{
|
|
Ctty: int(tty.Fd()),
|
|
Foreground: true,
|
|
}
|
|
cmd.Start()
|
|
cmd.Stop()
|
|
close(ch2)
|
|
}()
|
|
|
|
timer := time.NewTimer(30 * time.Second)
|
|
defer timer.Stop()
|
|
for {
|
|
select {
|
|
case sig := <-ch1:
|
|
t.Errorf("unexpected signal %v", sig)
|
|
case <-ch2:
|
|
// Success.
|
|
return
|
|
case <-timer.C:
|
|
t.Fatal("timed out waiting for child process")
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test a couple of cases that SysProcAttr can't handle. Issue 29458.
|
|
func TestInvalidExec(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("SetCtty-Foreground", func(t *testing.T) {
|
|
t.Parallel()
|
|
cmd := create(t)
|
|
cmd.proc.SysProcAttr = &syscall.SysProcAttr{
|
|
Setctty: true,
|
|
Foreground: true,
|
|
Ctty: 0,
|
|
}
|
|
if err := cmd.proc.Start(); err == nil {
|
|
t.Error("expected error setting both SetCtty and Foreground")
|
|
}
|
|
})
|
|
t.Run("invalid-Ctty", func(t *testing.T) {
|
|
t.Parallel()
|
|
cmd := create(t)
|
|
cmd.proc.SysProcAttr = &syscall.SysProcAttr{
|
|
Setctty: true,
|
|
Ctty: 3,
|
|
}
|
|
if err := cmd.proc.Start(); err == nil {
|
|
t.Error("expected error with invalid Ctty value")
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestExec is for issue #41702.
|
|
func TestExec(t *testing.T) {
|
|
testenv.MustHaveExec(t)
|
|
cmd := exec.Command(os.Args[0], "-test.run=TestExecHelper")
|
|
cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=2")
|
|
o, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
t.Errorf("%s\n%v", o, err)
|
|
}
|
|
}
|
|
|
|
// TestExecHelper is used by TestExec. It does nothing by itself.
|
|
// In testing on macOS 10.14, this used to fail with
|
|
// "signal: illegal instruction" more than half the time.
|
|
func TestExecHelper(t *testing.T) {
|
|
if os.Getenv("GO_WANT_HELPER_PROCESS") != "2" {
|
|
return
|
|
}
|
|
|
|
// We don't have to worry about restoring these values.
|
|
// We are in a child process that only runs this test,
|
|
// and we are going to call syscall.Exec anyhow.
|
|
os.Setenv("GO_WANT_HELPER_PROCESS", "3")
|
|
|
|
stop := time.Now().Add(time.Second)
|
|
for i := 0; i < 100; i++ {
|
|
go func(i int) {
|
|
r := rand.New(rand.NewSource(int64(i)))
|
|
for time.Now().Before(stop) {
|
|
r.Uint64()
|
|
}
|
|
}(i)
|
|
}
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
argv := []string{os.Args[0], "-test.run=TestExecHelper"}
|
|
syscall.Exec(os.Args[0], argv, os.Environ())
|
|
|
|
t.Error("syscall.Exec returned")
|
|
}
|