github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/runtime/testdata/testprogcgo/exec.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build !plan9,!windows
     6  
     7  package main
     8  
     9  /*
    10  #include <stddef.h>
    11  #include <signal.h>
    12  #include <pthread.h>
    13  
    14  // Save the signal mask at startup so that we see what it is before
    15  // the Go runtime starts setting up signals.
    16  
    17  static sigset_t mask;
    18  
    19  static void init(void) __attribute__ ((constructor));
    20  
    21  static void init() {
    22  	sigemptyset(&mask);
    23  	pthread_sigmask(SIG_SETMASK, NULL, &mask);
    24  }
    25  
    26  int SIGINTBlocked() {
    27  	return sigismember(&mask, SIGINT);
    28  }
    29  */
    30  import "C"
    31  
    32  import (
    33  	"fmt"
    34  	"io/fs"
    35  	"os"
    36  	"os/exec"
    37  	"os/signal"
    38  	"sync"
    39  	"syscall"
    40  )
    41  
    42  func init() {
    43  	register("CgoExecSignalMask", CgoExecSignalMask)
    44  }
    45  
    46  func CgoExecSignalMask() {
    47  	if len(os.Args) > 2 && os.Args[2] == "testsigint" {
    48  		if C.SIGINTBlocked() != 0 {
    49  			os.Exit(1)
    50  		}
    51  		os.Exit(0)
    52  	}
    53  
    54  	c := make(chan os.Signal, 1)
    55  	signal.Notify(c, syscall.SIGTERM)
    56  	go func() {
    57  		for range c {
    58  		}
    59  	}()
    60  
    61  	const goCount = 10
    62  	const execCount = 10
    63  	var wg sync.WaitGroup
    64  	wg.Add(goCount*execCount + goCount)
    65  	for i := 0; i < goCount; i++ {
    66  		go func() {
    67  			defer wg.Done()
    68  			for j := 0; j < execCount; j++ {
    69  				c2 := make(chan os.Signal, 1)
    70  				signal.Notify(c2, syscall.SIGUSR1)
    71  				syscall.Kill(os.Getpid(), syscall.SIGTERM)
    72  				go func(j int) {
    73  					defer wg.Done()
    74  					cmd := exec.Command(os.Args[0], "CgoExecSignalMask", "testsigint")
    75  					cmd.Stdin = os.Stdin
    76  					cmd.Stdout = os.Stdout
    77  					cmd.Stderr = os.Stderr
    78  					if err := cmd.Run(); err != nil {
    79  						// An overloaded system
    80  						// may fail with EAGAIN.
    81  						// This doesn't tell us
    82  						// anything useful; ignore it.
    83  						// Issue #27731.
    84  						if isEAGAIN(err) {
    85  							return
    86  						}
    87  						fmt.Printf("iteration %d: %v\n", j, err)
    88  						os.Exit(1)
    89  					}
    90  				}(j)
    91  				signal.Stop(c2)
    92  			}
    93  		}()
    94  	}
    95  	wg.Wait()
    96  
    97  	fmt.Println("OK")
    98  }
    99  
   100  // isEAGAIN reports whether err is an EAGAIN error from a process execution.
   101  func isEAGAIN(err error) bool {
   102  	if p, ok := err.(*fs.PathError); ok {
   103  		err = p.Err
   104  	}
   105  	return err == syscall.EAGAIN
   106  }