xref: /aosp_15_r20/external/swiftshader/tests/regres/shell/shell_unix.go (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1*03ce13f7SAndroid Build Coastguard Worker// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2*03ce13f7SAndroid Build Coastguard Worker//
3*03ce13f7SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*03ce13f7SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*03ce13f7SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*03ce13f7SAndroid Build Coastguard Worker//
7*03ce13f7SAndroid Build Coastguard Worker//    http://www.apache.org/licenses/LICENSE-2.0
8*03ce13f7SAndroid Build Coastguard Worker//
9*03ce13f7SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*03ce13f7SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*03ce13f7SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*03ce13f7SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*03ce13f7SAndroid Build Coastguard Worker// limitations under the License.
14*03ce13f7SAndroid Build Coastguard Worker
15*03ce13f7SAndroid Build Coastguard Worker//go:build darwin || linux
16*03ce13f7SAndroid Build Coastguard Worker// +build darwin linux
17*03ce13f7SAndroid Build Coastguard Worker
18*03ce13f7SAndroid Build Coastguard Workerpackage shell
19*03ce13f7SAndroid Build Coastguard Worker
20*03ce13f7SAndroid Build Coastguard Workerimport (
21*03ce13f7SAndroid Build Coastguard Worker	"bytes"
22*03ce13f7SAndroid Build Coastguard Worker	"fmt"
23*03ce13f7SAndroid Build Coastguard Worker	"log"
24*03ce13f7SAndroid Build Coastguard Worker	"os"
25*03ce13f7SAndroid Build Coastguard Worker	"os/exec"
26*03ce13f7SAndroid Build Coastguard Worker	"os/signal"
27*03ce13f7SAndroid Build Coastguard Worker	"strconv"
28*03ce13f7SAndroid Build Coastguard Worker	"syscall"
29*03ce13f7SAndroid Build Coastguard Worker	"time"
30*03ce13f7SAndroid Build Coastguard Worker)
31*03ce13f7SAndroid Build Coastguard Worker
32*03ce13f7SAndroid Build Coastguard Workerfunc init() {
33*03ce13f7SAndroid Build Coastguard Worker	// As we are going to be running a number of tests concurrently, we need to
34*03ce13f7SAndroid Build Coastguard Worker	// limit the amount of virtual memory each test uses, otherwise memory
35*03ce13f7SAndroid Build Coastguard Worker	// hungry tests can bring the whole system down into a swapping apocalypse.
36*03ce13f7SAndroid Build Coastguard Worker	//
37*03ce13f7SAndroid Build Coastguard Worker	// Linux has the setrlimit() function to limit a process (and child's)
38*03ce13f7SAndroid Build Coastguard Worker	// virtual memory usage - but we cannot call this from the regres process
39*03ce13f7SAndroid Build Coastguard Worker	// as this process may need more memory than the limit allows.
40*03ce13f7SAndroid Build Coastguard Worker	//
41*03ce13f7SAndroid Build Coastguard Worker	// Unfortunately golang has no native support for setting rlimits for child
42*03ce13f7SAndroid Build Coastguard Worker	// processes (https://github.com/golang/go/issues/6603), so we instead wrap
43*03ce13f7SAndroid Build Coastguard Worker	// the exec to the test executable with another child regres process using a
44*03ce13f7SAndroid Build Coastguard Worker	// special --exec mode:
45*03ce13f7SAndroid Build Coastguard Worker	//
46*03ce13f7SAndroid Build Coastguard Worker	// [regres] -> [regres --exec <test-exe N args...>] -> [test-exe]
47*03ce13f7SAndroid Build Coastguard Worker	//               ^^^^
48*03ce13f7SAndroid Build Coastguard Worker	//          (calls rlimit() with memory limit of N bytes)
49*03ce13f7SAndroid Build Coastguard Worker
50*03ce13f7SAndroid Build Coastguard Worker	if len(os.Args) > 3 && os.Args[1] == "--exec" {
51*03ce13f7SAndroid Build Coastguard Worker		exe := os.Args[2]
52*03ce13f7SAndroid Build Coastguard Worker		limit, err := strconv.ParseUint(os.Args[3], 10, 64)
53*03ce13f7SAndroid Build Coastguard Worker		if err != nil {
54*03ce13f7SAndroid Build Coastguard Worker			log.Fatalf("Expected memory limit as 3rd argument. %v\n", err)
55*03ce13f7SAndroid Build Coastguard Worker		}
56*03ce13f7SAndroid Build Coastguard Worker		if limit > 0 {
57*03ce13f7SAndroid Build Coastguard Worker			if err := syscall.Setrlimit(syscall.RLIMIT_AS, &syscall.Rlimit{Cur: limit, Max: limit}); err != nil {
58*03ce13f7SAndroid Build Coastguard Worker				log.Fatalln(fmt.Errorf("Setrlimit: %w", err))
59*03ce13f7SAndroid Build Coastguard Worker			}
60*03ce13f7SAndroid Build Coastguard Worker		}
61*03ce13f7SAndroid Build Coastguard Worker		cmd := exec.Command(exe, os.Args[4:]...)
62*03ce13f7SAndroid Build Coastguard Worker		cmd.Stdin = os.Stdin
63*03ce13f7SAndroid Build Coastguard Worker		cmd.Stdout = os.Stdout
64*03ce13f7SAndroid Build Coastguard Worker		cmd.Stderr = os.Stderr
65*03ce13f7SAndroid Build Coastguard Worker		if err := cmd.Start(); err != nil {
66*03ce13f7SAndroid Build Coastguard Worker			os.Stderr.WriteString(err.Error())
67*03ce13f7SAndroid Build Coastguard Worker			os.Exit(1)
68*03ce13f7SAndroid Build Coastguard Worker		}
69*03ce13f7SAndroid Build Coastguard Worker		// Forward signals to the child process
70*03ce13f7SAndroid Build Coastguard Worker		c := make(chan os.Signal, 1)
71*03ce13f7SAndroid Build Coastguard Worker		signal.Notify(c, os.Interrupt)
72*03ce13f7SAndroid Build Coastguard Worker		go func() {
73*03ce13f7SAndroid Build Coastguard Worker			for sig := range c {
74*03ce13f7SAndroid Build Coastguard Worker				cmd.Process.Signal(sig)
75*03ce13f7SAndroid Build Coastguard Worker			}
76*03ce13f7SAndroid Build Coastguard Worker		}()
77*03ce13f7SAndroid Build Coastguard Worker		cmd.Wait()
78*03ce13f7SAndroid Build Coastguard Worker		close(c)
79*03ce13f7SAndroid Build Coastguard Worker		os.Exit(cmd.ProcessState.ExitCode())
80*03ce13f7SAndroid Build Coastguard Worker	}
81*03ce13f7SAndroid Build Coastguard Worker}
82*03ce13f7SAndroid Build Coastguard Worker
83*03ce13f7SAndroid Build Coastguard Worker// Exec runs the executable exe with the given arguments, in the working
84*03ce13f7SAndroid Build Coastguard Worker// directory wd, with the custom environment flags.
85*03ce13f7SAndroid Build Coastguard Worker// If the process does not finish within timeout a errTimeout will be returned.
86*03ce13f7SAndroid Build Coastguard Workerfunc Exec(timeout time.Duration, exe, wd string, env []string, toStdin string, args ...string) ([]byte, error) {
87*03ce13f7SAndroid Build Coastguard Worker	stdin := &bytes.Buffer{}
88*03ce13f7SAndroid Build Coastguard Worker	stdin.WriteString(toStdin)
89*03ce13f7SAndroid Build Coastguard Worker
90*03ce13f7SAndroid Build Coastguard Worker	// Shell via regres: --exec N <exe> <args...>
91*03ce13f7SAndroid Build Coastguard Worker	// See main() for details.
92*03ce13f7SAndroid Build Coastguard Worker	args = append([]string{"--exec", exe, fmt.Sprintf("%v", MaxProcMemory)}, args...)
93*03ce13f7SAndroid Build Coastguard Worker	b := bytes.Buffer{}
94*03ce13f7SAndroid Build Coastguard Worker	c := exec.Command(os.Args[0], args...)
95*03ce13f7SAndroid Build Coastguard Worker	c.Dir = wd
96*03ce13f7SAndroid Build Coastguard Worker	c.Env = env
97*03ce13f7SAndroid Build Coastguard Worker	c.Stdin = stdin
98*03ce13f7SAndroid Build Coastguard Worker	c.Stdout = &b
99*03ce13f7SAndroid Build Coastguard Worker	c.Stderr = &b
100*03ce13f7SAndroid Build Coastguard Worker
101*03ce13f7SAndroid Build Coastguard Worker	if err := c.Start(); err != nil {
102*03ce13f7SAndroid Build Coastguard Worker		return nil, err
103*03ce13f7SAndroid Build Coastguard Worker	}
104*03ce13f7SAndroid Build Coastguard Worker
105*03ce13f7SAndroid Build Coastguard Worker	res := make(chan error)
106*03ce13f7SAndroid Build Coastguard Worker	go func() { res <- c.Wait() }()
107*03ce13f7SAndroid Build Coastguard Worker
108*03ce13f7SAndroid Build Coastguard Worker	select {
109*03ce13f7SAndroid Build Coastguard Worker	case <-time.NewTimer(timeout).C:
110*03ce13f7SAndroid Build Coastguard Worker		c.Process.Signal(syscall.SIGINT)
111*03ce13f7SAndroid Build Coastguard Worker		time.Sleep(time.Second * 3)
112*03ce13f7SAndroid Build Coastguard Worker		if c.ProcessState == nil || !c.ProcessState.Exited() {
113*03ce13f7SAndroid Build Coastguard Worker			log.Printf("Process %v still has not exited, killing\n", c.Process.Pid)
114*03ce13f7SAndroid Build Coastguard Worker			syscall.Kill(-c.Process.Pid, syscall.SIGKILL)
115*03ce13f7SAndroid Build Coastguard Worker		}
116*03ce13f7SAndroid Build Coastguard Worker		return b.Bytes(), ErrTimeout{exe, timeout}
117*03ce13f7SAndroid Build Coastguard Worker	case err := <-res:
118*03ce13f7SAndroid Build Coastguard Worker		return b.Bytes(), err
119*03ce13f7SAndroid Build Coastguard Worker	}
120*03ce13f7SAndroid Build Coastguard Worker}
121