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