package process
import (
"context"
"encoding/json"
"errors"
"runtime"
"sort"
"sync"
"time"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/internal/common"
"github.com/shirou/gopsutil/v3/mem"
"github.com/shirou/gopsutil/v3/net"
)
var (
invoke common .Invoker = common .Invoke {}
ErrorNoChildren = errors .New ("process does not have children" )
ErrorProcessNotRunning = errors .New ("process does not exist" )
ErrorNotPermitted = errors .New ("operation not permitted" )
)
type Process struct {
Pid int32 `json:"pid"`
name string
status string
parent int32
parentMutex sync .RWMutex
numCtxSwitches *NumCtxSwitchesStat
uids []int32
gids []int32
groups []int32
numThreads int32
memInfo *MemoryInfoStat
sigInfo *SignalInfoStat
createTime int64
lastCPUTimes *cpu .TimesStat
lastCPUTime time .Time
tgid int32
}
const (
Running = "running"
Blocked = "blocked"
Idle = "idle"
Lock = "lock"
Sleep = "sleep"
Stop = "stop"
Wait = "wait"
Zombie = "zombie"
Daemon = "daemon"
Detached = "detached"
System = "system"
Orphan = "orphan"
UnknownState = ""
)
type OpenFilesStat struct {
Path string `json:"path"`
Fd uint64 `json:"fd"`
}
type MemoryInfoStat struct {
RSS uint64 `json:"rss"`
VMS uint64 `json:"vms"`
HWM uint64 `json:"hwm"`
Data uint64 `json:"data"`
Stack uint64 `json:"stack"`
Locked uint64 `json:"locked"`
Swap uint64 `json:"swap"`
}
type SignalInfoStat struct {
PendingProcess uint64 `json:"pending_process"`
PendingThread uint64 `json:"pending_thread"`
Blocked uint64 `json:"blocked"`
Ignored uint64 `json:"ignored"`
Caught uint64 `json:"caught"`
}
type RlimitStat struct {
Resource int32 `json:"resource"`
Soft uint64 `json:"soft"`
Hard uint64 `json:"hard"`
Used uint64 `json:"used"`
}
type IOCountersStat struct {
ReadCount uint64 `json:"readCount"`
WriteCount uint64 `json:"writeCount"`
ReadBytes uint64 `json:"readBytes"`
WriteBytes uint64 `json:"writeBytes"`
}
type NumCtxSwitchesStat struct {
Voluntary int64 `json:"voluntary"`
Involuntary int64 `json:"involuntary"`
}
type PageFaultsStat struct {
MinorFaults uint64 `json:"minorFaults"`
MajorFaults uint64 `json:"majorFaults"`
ChildMinorFaults uint64 `json:"childMinorFaults"`
ChildMajorFaults uint64 `json:"childMajorFaults"`
}
const (
RLIMIT_CPU int32 = 0
RLIMIT_FSIZE int32 = 1
RLIMIT_DATA int32 = 2
RLIMIT_STACK int32 = 3
RLIMIT_CORE int32 = 4
RLIMIT_RSS int32 = 5
RLIMIT_NPROC int32 = 6
RLIMIT_NOFILE int32 = 7
RLIMIT_MEMLOCK int32 = 8
RLIMIT_AS int32 = 9
RLIMIT_LOCKS int32 = 10
RLIMIT_SIGPENDING int32 = 11
RLIMIT_MSGQUEUE int32 = 12
RLIMIT_NICE int32 = 13
RLIMIT_RTPRIO int32 = 14
RLIMIT_RTTIME int32 = 15
)
func (p Process ) String () string {
s , _ := json .Marshal (p )
return string (s )
}
func (o OpenFilesStat ) String () string {
s , _ := json .Marshal (o )
return string (s )
}
func (m MemoryInfoStat ) String () string {
s , _ := json .Marshal (m )
return string (s )
}
func (r RlimitStat ) String () string {
s , _ := json .Marshal (r )
return string (s )
}
func (i IOCountersStat ) String () string {
s , _ := json .Marshal (i )
return string (s )
}
func (p NumCtxSwitchesStat ) String () string {
s , _ := json .Marshal (p )
return string (s )
}
var enableBootTimeCache bool
func EnableBootTimeCache (enable bool ) {
enableBootTimeCache = enable
}
func Pids () ([]int32 , error ) {
return PidsWithContext (context .Background ())
}
func PidsWithContext (ctx context .Context ) ([]int32 , error ) {
pids , err := pidsWithContext (ctx )
sort .Slice (pids , func (i , j int ) bool { return pids [i ] < pids [j ] })
return pids , err
}
func Processes () ([]*Process , error ) {
return ProcessesWithContext (context .Background ())
}
func NewProcess (pid int32 ) (*Process , error ) {
return NewProcessWithContext (context .Background (), pid )
}
func NewProcessWithContext (ctx context .Context , pid int32 ) (*Process , error ) {
p := &Process {
Pid : pid ,
}
exists , err := PidExistsWithContext (ctx , pid )
if err != nil {
return p , err
}
if !exists {
return p , ErrorProcessNotRunning
}
p .CreateTimeWithContext (ctx )
return p , nil
}
func PidExists (pid int32 ) (bool , error ) {
return PidExistsWithContext (context .Background (), pid )
}
func (p *Process ) Background () (bool , error ) {
return p .BackgroundWithContext (context .Background ())
}
func (p *Process ) BackgroundWithContext (ctx context .Context ) (bool , error ) {
fg , err := p .ForegroundWithContext (ctx )
if err != nil {
return false , err
}
return !fg , err
}
func (p *Process ) Percent (interval time .Duration ) (float64 , error ) {
return p .PercentWithContext (context .Background (), interval )
}
func (p *Process ) PercentWithContext (ctx context .Context , interval time .Duration ) (float64 , error ) {
cpuTimes , err := p .TimesWithContext (ctx )
if err != nil {
return 0 , err
}
now := time .Now ()
if interval > 0 {
p .lastCPUTimes = cpuTimes
p .lastCPUTime = now
if err := common .Sleep (ctx , interval ); err != nil {
return 0 , err
}
cpuTimes , err = p .TimesWithContext (ctx )
now = time .Now ()
if err != nil {
return 0 , err
}
} else {
if p .lastCPUTimes == nil {
p .lastCPUTimes = cpuTimes
p .lastCPUTime = now
return 0 , nil
}
}
numcpu := runtime .NumCPU ()
delta := (now .Sub (p .lastCPUTime ).Seconds ()) * float64 (numcpu )
ret := calculatePercent (p .lastCPUTimes , cpuTimes , delta , numcpu )
p .lastCPUTimes = cpuTimes
p .lastCPUTime = now
return ret , nil
}
func (p *Process ) IsRunning () (bool , error ) {
return p .IsRunningWithContext (context .Background ())
}
func (p *Process ) IsRunningWithContext (ctx context .Context ) (bool , error ) {
createTime , err := p .CreateTimeWithContext (ctx )
if err != nil {
return false , err
}
p2 , err := NewProcessWithContext (ctx , p .Pid )
if errors .Is (err , ErrorProcessNotRunning ) {
return false , nil
}
createTime2 , err := p2 .CreateTimeWithContext (ctx )
if err != nil {
return false , err
}
return createTime == createTime2 , nil
}
func (p *Process ) CreateTime () (int64 , error ) {
return p .CreateTimeWithContext (context .Background ())
}
func (p *Process ) CreateTimeWithContext (ctx context .Context ) (int64 , error ) {
if p .createTime != 0 {
return p .createTime , nil
}
createTime , err := p .createTimeWithContext (ctx )
p .createTime = createTime
return p .createTime , err
}
func calculatePercent(t1 , t2 *cpu .TimesStat , delta float64 , numcpu int ) float64 {
if delta == 0 {
return 0
}
delta_proc := t2 .Total () - t1 .Total ()
overall_percent := ((delta_proc / delta ) * 100 ) * float64 (numcpu )
return overall_percent
}
func (p *Process ) MemoryPercent () (float32 , error ) {
return p .MemoryPercentWithContext (context .Background ())
}
func (p *Process ) MemoryPercentWithContext (ctx context .Context ) (float32 , error ) {
machineMemory , err := mem .VirtualMemoryWithContext (ctx )
if err != nil {
return 0 , err
}
total := machineMemory .Total
processMemory , err := p .MemoryInfoWithContext (ctx )
if err != nil {
return 0 , err
}
used := processMemory .RSS
return (100 * float32 (used ) / float32 (total )), nil
}
func (p *Process ) CPUPercent () (float64 , error ) {
return p .CPUPercentWithContext (context .Background ())
}
func (p *Process ) CPUPercentWithContext (ctx context .Context ) (float64 , error ) {
crt_time , err := p .createTimeWithContext (ctx )
if err != nil {
return 0 , err
}
cput , err := p .TimesWithContext (ctx )
if err != nil {
return 0 , err
}
created := time .Unix (0 , crt_time *int64 (time .Millisecond ))
totalTime := time .Since (created ).Seconds ()
if totalTime <= 0 {
return 0 , nil
}
return 100 * cput .Total () / totalTime , nil
}
func (p *Process ) Groups () ([]int32 , error ) {
return p .GroupsWithContext (context .Background ())
}
func (p *Process ) Ppid () (int32 , error ) {
return p .PpidWithContext (context .Background ())
}
func (p *Process ) Name () (string , error ) {
return p .NameWithContext (context .Background ())
}
func (p *Process ) Exe () (string , error ) {
return p .ExeWithContext (context .Background ())
}
func (p *Process ) Cmdline () (string , error ) {
return p .CmdlineWithContext (context .Background ())
}
func (p *Process ) CmdlineSlice () ([]string , error ) {
return p .CmdlineSliceWithContext (context .Background ())
}
func (p *Process ) Cwd () (string , error ) {
return p .CwdWithContext (context .Background ())
}
func (p *Process ) Parent () (*Process , error ) {
return p .ParentWithContext (context .Background ())
}
func (p *Process ) ParentWithContext (ctx context .Context ) (*Process , error ) {
ppid , err := p .PpidWithContext (ctx )
if err != nil {
return nil , err
}
return NewProcessWithContext (ctx , ppid )
}
func (p *Process ) Status () ([]string , error ) {
return p .StatusWithContext (context .Background ())
}
func (p *Process ) Foreground () (bool , error ) {
return p .ForegroundWithContext (context .Background ())
}
func (p *Process ) Uids () ([]int32 , error ) {
return p .UidsWithContext (context .Background ())
}
func (p *Process ) Gids () ([]int32 , error ) {
return p .GidsWithContext (context .Background ())
}
func (p *Process ) Terminal () (string , error ) {
return p .TerminalWithContext (context .Background ())
}
func (p *Process ) Nice () (int32 , error ) {
return p .NiceWithContext (context .Background ())
}
func (p *Process ) IOnice () (int32 , error ) {
return p .IOniceWithContext (context .Background ())
}
func (p *Process ) Rlimit () ([]RlimitStat , error ) {
return p .RlimitWithContext (context .Background ())
}
func (p *Process ) RlimitUsage (gatherUsed bool ) ([]RlimitStat , error ) {
return p .RlimitUsageWithContext (context .Background (), gatherUsed )
}
func (p *Process ) IOCounters () (*IOCountersStat , error ) {
return p .IOCountersWithContext (context .Background ())
}
func (p *Process ) NumCtxSwitches () (*NumCtxSwitchesStat , error ) {
return p .NumCtxSwitchesWithContext (context .Background ())
}
func (p *Process ) NumFDs () (int32 , error ) {
return p .NumFDsWithContext (context .Background ())
}
func (p *Process ) NumThreads () (int32 , error ) {
return p .NumThreadsWithContext (context .Background ())
}
func (p *Process ) Threads () (map [int32 ]*cpu .TimesStat , error ) {
return p .ThreadsWithContext (context .Background ())
}
func (p *Process ) Times () (*cpu .TimesStat , error ) {
return p .TimesWithContext (context .Background ())
}
func (p *Process ) CPUAffinity () ([]int32 , error ) {
return p .CPUAffinityWithContext (context .Background ())
}
func (p *Process ) MemoryInfo () (*MemoryInfoStat , error ) {
return p .MemoryInfoWithContext (context .Background ())
}
func (p *Process ) MemoryInfoEx () (*MemoryInfoExStat , error ) {
return p .MemoryInfoExWithContext (context .Background ())
}
func (p *Process ) PageFaults () (*PageFaultsStat , error ) {
return p .PageFaultsWithContext (context .Background ())
}
func (p *Process ) Children () ([]*Process , error ) {
return p .ChildrenWithContext (context .Background ())
}
func (p *Process ) OpenFiles () ([]OpenFilesStat , error ) {
return p .OpenFilesWithContext (context .Background ())
}
func (p *Process ) Connections () ([]net .ConnectionStat , error ) {
return p .ConnectionsWithContext (context .Background ())
}
func (p *Process ) ConnectionsMax (max int ) ([]net .ConnectionStat , error ) {
return p .ConnectionsMaxWithContext (context .Background (), max )
}
func (p *Process ) MemoryMaps (grouped bool ) (*[]MemoryMapsStat , error ) {
return p .MemoryMapsWithContext (context .Background (), grouped )
}
func (p *Process ) Tgid () (int32 , error ) {
return p .TgidWithContext (context .Background ())
}
func (p *Process ) SendSignal (sig Signal ) error {
return p .SendSignalWithContext (context .Background (), sig )
}
func (p *Process ) Suspend () error {
return p .SuspendWithContext (context .Background ())
}
func (p *Process ) Resume () error {
return p .ResumeWithContext (context .Background ())
}
func (p *Process ) Terminate () error {
return p .TerminateWithContext (context .Background ())
}
func (p *Process ) Kill () error {
return p .KillWithContext (context .Background ())
}
func (p *Process ) Username () (string , error ) {
return p .UsernameWithContext (context .Background ())
}
func (p *Process ) Environ () ([]string , error ) {
return p .EnvironWithContext (context .Background ())
}
func convertStatusChar(letter string ) string {
switch letter {
case "A" :
return Daemon
case "D" , "U" :
return Blocked
case "E" :
return Detached
case "I" :
return Idle
case "L" :
return Lock
case "O" :
return Orphan
case "R" :
return Running
case "S" :
return Sleep
case "T" , "t" :
return Stop
case "W" :
return Wait
case "Y" :
return System
case "Z" :
return Zombie
default :
return UnknownState
}
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .