golang.org/x/build@v0.0.0-20240506185731-218518f32b70/cmd/buildlet/buildlet_windows.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  package main
     6  
     7  import (
     8  	"log"
     9  	"os"
    10  	"syscall"
    11  	"unsafe"
    12  
    13  	"github.com/tarm/serial"
    14  )
    15  
    16  func init() {
    17  	killProcessTree = killProcessTreeWindows
    18  	configureSerialLogOutput = configureSerialLogOutputWindows
    19  }
    20  
    21  func configureSerialLogOutputWindows() {
    22  	c := &serial.Config{Name: "COM1", Baud: 9600}
    23  	s, err := serial.OpenPort(c)
    24  	if err != nil {
    25  		// Oh well, we tried. This empirically works
    26  		// on Windows on GCE.
    27  		// We can log here anyway and hope somebody sees it
    28  		// in a GUI console:
    29  		log.Printf("serial.OpenPort: %v", err)
    30  		return
    31  	}
    32  	log.SetOutput(s)
    33  }
    34  
    35  // the system process tree
    36  type psTree map[int]int // pid -> parent pid
    37  
    38  // findDescendants searches process tree t for pid process children.
    39  // It returns children pids.
    40  func (t psTree) findDescendants(pid int) []int {
    41  	var children []int
    42  	for child, parent := range t {
    43  		if parent == pid {
    44  			children = append(children, child)
    45  			children = append(children, t.findDescendants(child)...)
    46  		}
    47  	}
    48  	return children
    49  }
    50  
    51  func snapshotSysProcesses() (psTree, error) {
    52  	ss, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  	defer syscall.CloseHandle(ss)
    57  
    58  	ps := make(psTree)
    59  
    60  	var pe syscall.ProcessEntry32
    61  	pe.Size = uint32(unsafe.Sizeof(pe))
    62  	if err = syscall.Process32First(ss, &pe); err != nil {
    63  		return nil, err
    64  	}
    65  	for {
    66  		ps[int(pe.ProcessID)] = int(pe.ParentProcessID)
    67  		err = syscall.Process32Next(ss, &pe)
    68  		if err == syscall.ERROR_NO_MORE_FILES {
    69  			return ps, nil
    70  		}
    71  		if err != nil {
    72  			return nil, err
    73  		}
    74  	}
    75  }
    76  
    77  func killProcesses(ps []int) {
    78  	for _, pid := range ps {
    79  		p, err := os.FindProcess(pid)
    80  		if err != nil {
    81  			continue
    82  		}
    83  		p.Kill()
    84  		p.Release()
    85  	}
    86  }
    87  
    88  func killProcessTreeWindows(p *os.Process) error {
    89  	ps, err := snapshotSysProcesses()
    90  	if err != nil {
    91  		return err
    92  	}
    93  	toKill := ps.findDescendants(p.Pid)
    94  	toKill = append(toKill, p.Pid)
    95  	killProcesses(toKill)
    96  	return nil
    97  }