Source file src/runtime/testdata/testprogcgo/exec.go

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

View as plain text