1
0
mirror of https://github.com/shirou/gopsutil.git synced 2025-04-26 13:48:59 +08:00

Merge branch 'master' of github.com:shirou/gopsutil into feature/lxd_boot_time

This commit is contained in:
shirou 2018-01-09 11:16:18 +09:00
commit 8b2468f1e7
21 changed files with 334 additions and 84 deletions

View File

@ -43,7 +43,7 @@ Available Architectures
- Linux i386/amd64/arm(raspberry pi)
- Windows/amd64
- Darwin i386/amd64
- OpenBDS amd64 (Thank you @mpfz0r!)
- OpenBSD amd64 (Thank you @mpfz0r!)
- Solaris amd64 (developed and tested on SmartOS/Illumos, Thank you @jen20!)
All works are implemented without cgo by porting c struct to golang struct.
@ -187,7 +187,7 @@ boot_time x x x x x
users x x x x x
pids x x x x x
pid_exists x x x x x
net_connections x x
net_connections x x x
net_protocols x
net_if_addrs
net_if_stats

View File

@ -12,6 +12,9 @@ import (
"github.com/shirou/gopsutil/internal/common"
)
// TimesStat contains the amounts of time the CPU has spent performing different
// kinds of work. Time units are in USER_HZ or Jiffies (typically hundredths of
// a second). It is based on linux /proc/stat file.
type TimesStat struct {
CPU string `json:"cpu"`
User float64 `json:"user"`

View File

@ -3,6 +3,7 @@
package cpu
import (
"context"
"fmt"
"unsafe"
@ -81,8 +82,9 @@ func Info() ([]InfoStat, error) {
var ret []InfoStat
var dst []Win32_Processor
q := wmi.CreateQuery(&dst, "")
err := wmi.Query(q, &dst)
if err != nil {
ctx, cancel := context.WithTimeout(context.Background(), common.Timeout)
defer cancel()
if err := common.WMIQueryWithContext(ctx, q, &dst); err != nil {
return ret, err
}
@ -113,8 +115,11 @@ func Info() ([]InfoStat, error) {
// Name property is the key by which overall, per cpu and per core metric is known.
func PerfInfo() ([]Win32_PerfFormattedData_Counters_ProcessorInformation, error) {
var ret []Win32_PerfFormattedData_Counters_ProcessorInformation
q := wmi.CreateQuery(&ret, "")
err := wmi.Query(q, &ret)
ctx, cancel := context.WithTimeout(context.Background(), common.Timeout)
defer cancel()
err := common.WMIQueryWithContext(ctx, q, &ret)
return ret, err
}
@ -123,7 +128,9 @@ func PerfInfo() ([]Win32_PerfFormattedData_Counters_ProcessorInformation, error)
func ProcInfo() ([]Win32_PerfFormattedData_PerfOS_System, error) {
var ret []Win32_PerfFormattedData_PerfOS_System
q := wmi.CreateQuery(&ret, "")
err := wmi.Query(q, &ret)
ctx, cancel := context.WithTimeout(context.Background(), common.Timeout)
defer cancel()
err := common.WMIQueryWithContext(ctx, q, &ret)
return ret, err
}

View File

@ -66,7 +66,7 @@ func Partitions(all bool) ([]PartitionStat, error) {
func IOCounters(names ...string) (map[string]IOCountersStat, error) {
ret := make(map[string]IOCountersStat)
r, err := unix.Sysctl("hw.diskstats")
r, err := unix.SysctlRaw("hw.diskstats")
if err != nil {
return nil, err
}

View File

@ -4,9 +4,9 @@ package disk
import (
"bytes"
"context"
"unsafe"
"github.com/StackExchange/wmi"
"github.com/shirou/gopsutil/internal/common"
"golang.org/x/sys/windows"
)
@ -132,7 +132,9 @@ func IOCounters(names ...string) (map[string]IOCountersStat, error) {
ret := make(map[string]IOCountersStat, 0)
var dst []Win32_PerfFormattedData
err := wmi.Query("SELECT * FROM Win32_PerfFormattedData_PerfDisk_LogicalDisk ", &dst)
ctx, cancel := context.WithTimeout(context.Background(), common.Timeout)
defer cancel()
err := common.WMIQueryWithContext(ctx, "SELECT * FROM Win32_PerfFormattedData_PerfDisk_LogicalDisk", &dst)
if err != nil {
return ret, err
}

View File

@ -1,6 +1,7 @@
package docker
import (
"encoding/json"
"errors"
"github.com/shirou/gopsutil/internal/common"
@ -50,6 +51,11 @@ type CgroupMemStat struct {
MemFailCnt uint64 `json:"memoryFailcnt"`
}
func (m CgroupMemStat) String() string {
s, _ := json.Marshal(m)
return string(s)
}
type CgroupDockerStat struct {
ContainerID string `json:"containerID"`
Name string `json:"name"`
@ -57,3 +63,8 @@ type CgroupDockerStat struct {
Status string `json:"status"`
Running bool `json:"running"`
}
func (c CgroupDockerStat) String() string {
s, _ := json.Marshal(c)
return string(s)
}

View File

@ -3,7 +3,6 @@
package docker
import (
"encoding/json"
"fmt"
"os"
"os/exec"
@ -52,11 +51,6 @@ func GetDockerStat() ([]CgroupDockerStat, error) {
return ret, nil
}
func (c CgroupDockerStat) String() string {
s, _ := json.Marshal(c)
return string(s)
}
// GetDockerIDList returnes a list of DockerID.
// This requires certain permission.
func GetDockerIDList() ([]string, error) {
@ -220,11 +214,6 @@ func CgroupMemDocker(containerID string) (*CgroupMemStat, error) {
return CgroupMem(containerID, common.HostSys("fs/cgroup/memory/docker"))
}
func (m CgroupMemStat) String() string {
s, _ := json.Marshal(m)
return string(s)
}
// getCgroupFilePath constructs file path to get targetted stats file.
func getCgroupFilePath(containerID, base, target, file string) string {
if len(base) == 0 {

View File

@ -552,7 +552,7 @@ func SensorsTemperatures() ([]TemperatureStat, error) {
if len(files) == 0 {
// CentOS has an intermediate /device directory:
// https://github.com/giampaolo/psutil/issues/971
files, err = filepath.Glob(common.HostSys("/class/hwmon/hwmon*/temp*_*"))
files, err = filepath.Glob(common.HostSys("/class/hwmon/hwmon*/device/temp*_*"))
if err != nil {
return temperatures, err
}
@ -568,12 +568,12 @@ func SensorsTemperatures() ([]TemperatureStat, error) {
if err != nil {
return temperatures, err
}
temperature, err := strconv.ParseFloat(string(current), 64)
temperature, err := strconv.ParseFloat(strings.TrimSpace(string(current)), 64)
if err != nil {
continue
}
temperatures = append(temperatures, TemperatureStat{
SensorKey: string(name),
SensorKey: strings.TrimSpace(string(name)),
Temperature: temperature / 1000.0,
})
}

View File

@ -56,7 +56,7 @@ func TestUsers(t *testing.T) {
}
empty := UserStat{}
if len(v) == 0 {
t.Errorf("Users is empty")
t.Fatal("Users is empty")
}
for _, u := range v {
if u == empty {

View File

@ -3,6 +3,7 @@
package host
import (
"context"
"fmt"
"os"
"runtime"
@ -109,7 +110,9 @@ func getMachineGuid() (string, error) {
func GetOSInfo() (Win32_OperatingSystem, error) {
var dst []Win32_OperatingSystem
q := wmi.CreateQuery(&dst, "")
err := wmi.Query(q, &dst)
ctx, cancel := context.WithTimeout(context.Background(), common.Timeout)
defer cancel()
err := common.WMIQueryWithContext(ctx, q, &dst)
if err != nil {
return Win32_OperatingSystem{}, err
}

View File

@ -3,8 +3,10 @@
package common
import (
"context"
"unsafe"
"github.com/StackExchange/wmi"
"golang.org/x/sys/windows"
)
@ -49,7 +51,7 @@ var (
ModNt = windows.NewLazyDLL("ntdll.dll")
ModPdh = windows.NewLazyDLL("pdh.dll")
ModPsapi = windows.NewLazyDLL("psapi.dll")
ProcGetSystemTimes = Modkernel32.NewProc("GetSystemTimes")
ProcNtQuerySystemInformation = ModNt.NewProc("NtQuerySystemInformation")
PdhOpenQuery = ModPdh.NewProc("PdhOpenQuery")
@ -110,3 +112,18 @@ func CreateCounter(query windows.Handle, pname, cname string) (*CounterInfo, err
Counter: counter,
}, nil
}
// WMIQueryWithContext - wraps wmi.Query with a timed-out context to avoid hanging
func WMIQueryWithContext(ctx context.Context, query string, dst interface{}, connectServerArgs ...interface{}) error {
errChan := make(chan error, 1)
go func() {
errChan <- wmi.Query(query, dst, connectServerArgs...)
}()
select {
case <-ctx.Done():
return ctx.Err()
case err := <-errChan:
return err
}
}

View File

@ -541,8 +541,8 @@ func getProcInodesAll(root string, max int) (map[string][]inodeMap, error) {
for _, pid := range pids {
t, err := getProcInodes(root, pid, max)
if err != nil {
// skip if permission error
if os.IsPermission(err) {
// skip if permission error or no longer exists
if os.IsPermission(err) || os.IsNotExist(err) {
continue
}
return ret, err

View File

@ -4,13 +4,18 @@ package net
import (
"errors"
"fmt"
"os/exec"
"regexp"
"strconv"
"strings"
"syscall"
"github.com/shirou/gopsutil/internal/common"
)
var portMatch = regexp.MustCompile(`(.*)\.(\d+)$`)
func ParseNetstat(output string, mode string,
iocs map[string]IOCountersStat) error {
lines := strings.Split(output, "\n")
@ -92,7 +97,7 @@ func ParseNetstat(output string, mode string,
}
func IOCounters(pernic bool) ([]IOCountersStat, error) {
netstat, err := exec.LookPath("/usr/bin/netstat")
netstat, err := exec.LookPath("netstat")
if err != nil {
return nil, err
}
@ -146,8 +151,141 @@ func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
return nil, errors.New("NetProtoCounters not implemented for openbsd")
}
// Return a list of network connections opened.
// Not Implemented for OpenBSD
func Connections(kind string) ([]ConnectionStat, error) {
return nil, errors.New("Connections not implemented for openbsd")
func parseNetstatLine(line string) (ConnectionStat, error) {
f := strings.Fields(line)
if len(f) < 5 {
return ConnectionStat{}, fmt.Errorf("wrong line,%s", line)
}
var netType, netFamily uint32
switch f[0] {
case "tcp":
netType = syscall.SOCK_STREAM
netFamily = syscall.AF_INET
case "udp":
netType = syscall.SOCK_DGRAM
netFamily = syscall.AF_INET
case "tcp6":
netType = syscall.SOCK_STREAM
netFamily = syscall.AF_INET6
case "udp6":
netType = syscall.SOCK_DGRAM
netFamily = syscall.AF_INET6
default:
return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[0])
}
laddr, raddr, err := parseNetstatAddr(f[3], f[4], netFamily)
if err != nil {
return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s %s", f[3], f[4])
}
n := ConnectionStat{
Fd: uint32(0), // not supported
Family: uint32(netFamily),
Type: uint32(netType),
Laddr: laddr,
Raddr: raddr,
Pid: int32(0), // not supported
}
if len(f) == 6 {
n.Status = f[5]
}
return n, nil
}
func parseNetstatAddr(local string, remote string, family uint32) (laddr Addr, raddr Addr, err error) {
parse := func(l string) (Addr, error) {
matches := portMatch.FindStringSubmatch(l)
if matches == nil {
return Addr{}, fmt.Errorf("wrong addr, %s", l)
}
host := matches[1]
port := matches[2]
if host == "*" {
switch family {
case syscall.AF_INET:
host = "0.0.0.0"
case syscall.AF_INET6:
host = "::"
default:
return Addr{}, fmt.Errorf("unknown family, %d", family)
}
}
lport, err := strconv.Atoi(port)
if err != nil {
return Addr{}, err
}
return Addr{IP: host, Port: uint32(lport)}, nil
}
laddr, err = parse(local)
if remote != "*.*" { // remote addr exists
raddr, err = parse(remote)
if err != nil {
return laddr, raddr, err
}
}
return laddr, raddr, err
}
// Return a list of network connections opened.
func Connections(kind string) ([]ConnectionStat, error) {
var ret []ConnectionStat
args := []string{"-na"}
switch strings.ToLower(kind) {
default:
fallthrough
case "":
fallthrough
case "all":
fallthrough
case "inet":
// nothing to add
case "inet4":
args = append(args, "-finet")
case "inet6":
args = append(args, "-finet6")
case "tcp":
args = append(args, "-ptcp")
case "tcp4":
args = append(args, "-ptcp", "-finet")
case "tcp6":
args = append(args, "-ptcp", "-finet6")
case "udp":
args = append(args, "-pudp")
case "udp4":
args = append(args, "-pudp", "-finet")
case "udp6":
args = append(args, "-pudp", "-finet6")
case "unix":
return ret, common.ErrNotImplementedError
}
netstat, err := exec.LookPath("netstat")
if err != nil {
return nil, err
}
out, err := invoke.Command(netstat, args...)
if err != nil {
return nil, err
}
lines := strings.Split(string(out), "\n")
for _, line := range lines {
if !(strings.HasPrefix(line, "tcp") || strings.HasPrefix(line, "udp")) {
continue
}
n, err := parseNetstatLine(line)
if err != nil {
continue
}
ret = append(ret, n)
}
return ret, nil
}

View File

@ -30,6 +30,8 @@ type Process struct {
lastCPUTimes *cpu.TimesStat
lastCPUTime time.Time
tgid int32
}
type OpenFilesStat struct {

View File

@ -83,6 +83,9 @@ func (p *Process) Name() (string, error) {
return common.IntToString(k.Proc.P_comm[:]), nil
}
func (p *Process) Tgid() (int32, error) {
return 0, common.ErrNotImplementedError
}
func (p *Process) Exe() (string, error) {
lsof_bin, err := exec.LookPath("lsof")
if err != nil {
@ -390,8 +393,8 @@ func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
return &ret, common.ErrNotImplementedError
}
func processes() ([]Process, error) {
results := make([]Process, 0, 50)
func Processes() ([]*Process, error) {
results := []*Process{}
mib := []int32{CTLKern, KernProc, KernProcAll, 0}
buf, length, err := common.CallSyscall(mib)
@ -403,13 +406,6 @@ func processes() ([]Process, error) {
k := KinfoProc{}
procinfoLen := int(unsafe.Sizeof(k))
count := int(length / uint64(procinfoLen))
/*
fmt.Println(length, procinfoLen, count)
b := buf[0*procinfoLen : 0*procinfoLen+procinfoLen]
fmt.Println(b)
kk, err := parseKinfoProc(b)
fmt.Printf("%#v", kk)
*/
// parse buf to procs
for i := 0; i < count; i++ {
@ -422,7 +418,7 @@ func processes() ([]Process, error) {
if err != nil {
continue
}
results = append(results, *p)
results = append(results, p)
}
return results, nil

View File

@ -41,6 +41,9 @@ func (p *Process) Ppid() (int32, error) {
func (p *Process) Name() (string, error) {
return "", common.ErrNotImplementedError
}
func (p *Process) Tgid() (int32, error) {
return 0, common.ErrNotImplementedError
}
func (p *Process) Exe() (string, error) {
return "", common.ErrNotImplementedError
}

View File

@ -22,7 +22,7 @@ type MemoryMapsStat struct {
func Pids() ([]int32, error) {
var ret []int32
procs, err := processes()
procs, err := Processes()
if err != nil {
return ret, nil
}
@ -50,6 +50,9 @@ func (p *Process) Name() (string, error) {
return common.IntToString(k.Comm[:]), nil
}
func (p *Process) Tgid() (int32, error) {
return 0, common.ErrNotImplementedError
}
func (p *Process) Exe() (string, error) {
return "", common.ErrNotImplementedError
}
@ -278,8 +281,8 @@ func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
return &ret, common.ErrNotImplementedError
}
func processes() ([]Process, error) {
results := make([]Process, 0, 50)
func Processes() ([]*Process, error) {
results := []*Process{}
mib := []int32{CTLKern, KernProc, KernProcProc, 0}
buf, length, err := common.CallSyscall(mib)
@ -302,7 +305,7 @@ func processes() ([]Process, error) {
continue
}
results = append(results, *p)
results = append(results, p)
}
return results, nil

View File

@ -100,6 +100,16 @@ func (p *Process) Name() (string, error) {
return p.name, nil
}
// Tgid returns tgid, a Linux-synonym for user-space Pid
func (p *Process) Tgid() (int32, error) {
if p.tgid == 0 {
if err := p.fillFromStatus(); err != nil {
return 0, err
}
}
return p.tgid, nil
}
// Exe returns executable path of the process.
func (p *Process) Exe() (string, error) {
return p.fillFromExe()
@ -820,6 +830,12 @@ func (p *Process) fillFromStatus() error {
return err
}
p.parent = int32(pval)
case "Tgid":
pval, err := strconv.ParseInt(value, 10, 32)
if err != nil {
return err
}
p.tgid = int32(pval)
case "Uid":
p.uids = make([]int32, 0, 4)
for _, i := range strings.Split(value, "\t") {
@ -1017,6 +1033,27 @@ func Pids() ([]int32, error) {
return readPidsFromDir(common.HostProc())
}
// Process returns a slice of pointers to Process structs for all
// currently running processes.
func Processes() ([]*Process, error) {
out := []*Process{}
pids, err := Pids()
if err != nil {
return out, err
}
for _, pid := range pids {
p, err := NewProcess(pid)
if err != nil {
continue
}
out = append(out, p)
}
return out, nil
}
func readPidsFromDir(path string) ([]int32, error) {
var ret []int32

View File

@ -25,7 +25,7 @@ type MemoryMapsStat struct {
func Pids() ([]int32, error) {
var ret []int32
procs, err := processes()
procs, err := Processes()
if err != nil {
return ret, nil
}
@ -53,6 +53,9 @@ func (p *Process) Name() (string, error) {
return common.IntToString(k.Comm[:]), nil
}
func (p *Process) Tgid() (int32, error) {
return 0, common.ErrNotImplementedError
}
func (p *Process) Exe() (string, error) {
return "", common.ErrNotImplementedError
}
@ -268,8 +271,8 @@ func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
return &ret, common.ErrNotImplementedError
}
func processes() ([]Process, error) {
results := make([]Process, 0, 50)
func Processes() ([]*Process, error) {
results := []*Process{}
buf, length, err := CallKernProcSyscall(KernProcAll, 0)
@ -292,7 +295,7 @@ func processes() ([]Process, error) {
continue
}
results = append(results, *p)
results = append(results, p)
}
return results, nil

View File

@ -3,6 +3,7 @@ package process
import (
"fmt"
"os"
"os/exec"
"os/user"
"reflect"
"runtime"
@ -418,5 +419,24 @@ func Test_OpenFiles(t *testing.T) {
for _, vv := range v {
assert.NotEqual(t, "", vv.Path)
}
}
func Test_Kill(t *testing.T) {
var cmd *exec.Cmd
if runtime.GOOS == "windows" {
cmd = exec.Command("choice", "/C", "YN", "/D", "Y", "/t", "3")
} else {
cmd = exec.Command("sleep", "3")
}
var wg sync.WaitGroup
wg.Add(1)
go func() {
assert.NotNil(t, cmd.Run())
wg.Done()
}()
time.Sleep(100 * time.Millisecond)
p, err := NewProcess(int32(cmd.Process.Pid))
assert.Nil(t, err)
assert.Nil(t, p.Kill())
wg.Wait()
}

View File

@ -3,7 +3,9 @@
package process
import (
"context"
"fmt"
"os"
"strings"
"syscall"
"time"
@ -93,35 +95,47 @@ func init() {
}
func Pids() ([]int32, error) {
// inspired by https://gist.github.com/henkman/3083408
// and https://github.com/giampaolo/psutil/blob/1c3a15f637521ba5c0031283da39c733fda53e4c/psutil/arch/windows/process_info.c#L315-L329
var ret []int32
var read uint32 = 0
var psSize uint32 = 1024
const dwordSize uint32 = 4
procs, err := processes()
if err != nil {
for {
ps := make([]uint32, psSize)
if !w32.EnumProcesses(ps, uint32(len(ps)), &read) {
return nil, fmt.Errorf("could not get w32.EnumProcesses")
}
if uint32(len(ps)) == read { // ps buffer was too small to host every results, retry with a bigger one
psSize += 1024
continue
}
for _, pid := range ps[:read/dwordSize] {
ret = append(ret, int32(pid))
}
return ret, nil
}
for _, proc := range procs {
ret = append(ret, proc.Pid)
}
return ret, nil
}
func (p *Process) Ppid() (int32, error) {
dst, err := GetWin32Proc(p.Pid)
ppid, _, _, err := getFromSnapProcess(p.Pid)
if err != nil {
return 0, err
}
return int32(dst[0].ParentProcessID), nil
return ppid, nil
}
func GetWin32Proc(pid int32) ([]Win32_Process, error) {
var dst []Win32_Process
query := fmt.Sprintf("WHERE ProcessId = %d", pid)
q := wmi.CreateQuery(&dst, query)
if err := wmi.Query(q, &dst); err != nil {
ctx, cancel := context.WithTimeout(context.Background(), common.Timeout)
defer cancel()
err := common.WMIQueryWithContext(ctx, q, &dst)
if err != nil {
return []Win32_Process{}, fmt.Errorf("could not get win32Proc: %s", err)
}
@ -133,11 +147,15 @@ func GetWin32Proc(pid int32) ([]Win32_Process, error) {
}
func (p *Process) Name() (string, error) {
dst, err := GetWin32Proc(p.Pid)
_, _, name, err := getFromSnapProcess(p.Pid)
if err != nil {
return "", fmt.Errorf("could not get Name: %s", err)
}
return dst[0].Name, nil
return name, nil
}
func (p *Process) Tgid() (int32, error) {
return 0, common.ErrNotImplementedError
}
func (p *Process) Exe() (string, error) {
@ -292,11 +310,11 @@ func (p *Process) Times() (*cpu.TimesStat, error) {
// below from psutil's _psutil_windows.c, and in turn from Python's
// Modules/posixmodule.c
user := float64(sysTimes.UserTime.HighDateTime) * 429.4967296 + float64(sysTimes.UserTime.LowDateTime) * 1e-7
kernel := float64(sysTimes.KernelTime.HighDateTime) * 429.4967296 + float64(sysTimes.KernelTime.LowDateTime) * 1e-7
user := float64(sysTimes.UserTime.HighDateTime)*429.4967296 + float64(sysTimes.UserTime.LowDateTime)*1e-7
kernel := float64(sysTimes.KernelTime.HighDateTime)*429.4967296 + float64(sysTimes.KernelTime.LowDateTime)*1e-7
return &cpu.TimesStat{
User: user,
User: user,
System: kernel,
}, nil
}
@ -323,7 +341,9 @@ func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
func (p *Process) Children() ([]*Process, error) {
var dst []Win32_Process
query := wmi.CreateQuery(&dst, fmt.Sprintf("Where ParentProcessId = %d", p.Pid))
err := wmi.Query(query, &dst)
ctx, cancel := context.WithTimeout(context.Background(), common.Timeout)
defer cancel()
err := common.WMIQueryWithContext(ctx, query, &dst)
if err != nil {
return nil, err
}
@ -392,10 +412,11 @@ func (p *Process) Terminate() error {
}
func (p *Process) Kill() error {
return common.ErrNotImplementedError
process := os.Process{Pid: int(p.Pid)}
return process.Kill()
}
func (p *Process) getFromSnapProcess(pid int32) (int32, int32, string, error) {
func getFromSnapProcess(pid int32) (int32, int32, string, error) {
snap := w32.CreateToolhelp32Snapshot(w32.TH32CS_SNAPPROCESS, uint32(pid))
if snap == 0 {
return 0, 0, "", windows.GetLastError()
@ -422,20 +443,15 @@ func (p *Process) getFromSnapProcess(pid int32) (int32, int32, string, error) {
}
// Get processes
func processes() ([]*Process, error) {
var dst []Win32_Process
q := wmi.CreateQuery(&dst, "")
err := wmi.Query(q, &dst)
func Processes() ([]*Process, error) {
pids, err := Pids()
if err != nil {
return []*Process{}, err
}
if len(dst) == 0 {
return []*Process{}, fmt.Errorf("could not get Process")
return []*Process{}, fmt.Errorf("could not get Processes %s", err)
}
results := []*Process{}
for _, proc := range dst {
p, err := NewProcess(int32(proc.ProcessID))
for _, pid := range pids {
p, err := NewProcess(int32(pid))
if err != nil {
continue
}
@ -508,9 +524,9 @@ func getProcessMemoryInfo(h windows.Handle, mem *PROCESS_MEMORY_COUNTERS) (err e
type SYSTEM_TIMES struct {
CreateTime syscall.Filetime
ExitTime syscall.Filetime
ExitTime syscall.Filetime
KernelTime syscall.Filetime
UserTime syscall.Filetime
UserTime syscall.Filetime
}
func getProcessCPUTimes(pid int32) (SYSTEM_TIMES, error) {