process.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. package process
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "runtime"
  7. "sort"
  8. "sync"
  9. "time"
  10. "github.com/shirou/gopsutil/v3/cpu"
  11. "github.com/shirou/gopsutil/v3/internal/common"
  12. "github.com/shirou/gopsutil/v3/mem"
  13. "github.com/shirou/gopsutil/v3/net"
  14. )
  15. var (
  16. invoke common.Invoker = common.Invoke{}
  17. ErrorNoChildren = errors.New("process does not have children")
  18. ErrorProcessNotRunning = errors.New("process does not exist")
  19. ErrorNotPermitted = errors.New("operation not permitted")
  20. )
  21. type Process struct {
  22. Pid int32 `json:"pid"`
  23. name string
  24. status string
  25. parent int32
  26. parentMutex sync.RWMutex // for windows ppid cache
  27. numCtxSwitches *NumCtxSwitchesStat
  28. uids []int32
  29. gids []int32
  30. groups []int32
  31. numThreads int32
  32. memInfo *MemoryInfoStat
  33. sigInfo *SignalInfoStat
  34. createTime int64
  35. lastCPUTimes *cpu.TimesStat
  36. lastCPUTime time.Time
  37. tgid int32
  38. }
  39. // Process status
  40. const (
  41. // Running marks a task a running or runnable (on the run queue)
  42. Running = "running"
  43. // Blocked marks a task waiting on a short, uninterruptible operation (usually I/O)
  44. Blocked = "blocked"
  45. // Idle marks a task sleeping for more than about 20 seconds
  46. Idle = "idle"
  47. // Lock marks a task waiting to acquire a lock
  48. Lock = "lock"
  49. // Sleep marks task waiting for short, interruptible operation
  50. Sleep = "sleep"
  51. // Stop marks a stopped process
  52. Stop = "stop"
  53. // Wait marks an idle interrupt thread (or paging in pre 2.6.xx Linux)
  54. Wait = "wait"
  55. // Zombie marks a defunct process, terminated but not reaped by its parent
  56. Zombie = "zombie"
  57. // Solaris states. See https://github.com/collectd/collectd/blob/1da3305c10c8ff9a63081284cf3d4bb0f6daffd8/src/processes.c#L2115
  58. Daemon = "daemon"
  59. Detached = "detached"
  60. System = "system"
  61. Orphan = "orphan"
  62. UnknownState = ""
  63. )
  64. type OpenFilesStat struct {
  65. Path string `json:"path"`
  66. Fd uint64 `json:"fd"`
  67. }
  68. type MemoryInfoStat struct {
  69. RSS uint64 `json:"rss"` // bytes
  70. VMS uint64 `json:"vms"` // bytes
  71. HWM uint64 `json:"hwm"` // bytes
  72. Data uint64 `json:"data"` // bytes
  73. Stack uint64 `json:"stack"` // bytes
  74. Locked uint64 `json:"locked"` // bytes
  75. Swap uint64 `json:"swap"` // bytes
  76. }
  77. type SignalInfoStat struct {
  78. PendingProcess uint64 `json:"pending_process"`
  79. PendingThread uint64 `json:"pending_thread"`
  80. Blocked uint64 `json:"blocked"`
  81. Ignored uint64 `json:"ignored"`
  82. Caught uint64 `json:"caught"`
  83. }
  84. type RlimitStat struct {
  85. Resource int32 `json:"resource"`
  86. Soft uint64 `json:"soft"`
  87. Hard uint64 `json:"hard"`
  88. Used uint64 `json:"used"`
  89. }
  90. type IOCountersStat struct {
  91. ReadCount uint64 `json:"readCount"`
  92. WriteCount uint64 `json:"writeCount"`
  93. ReadBytes uint64 `json:"readBytes"`
  94. WriteBytes uint64 `json:"writeBytes"`
  95. }
  96. type NumCtxSwitchesStat struct {
  97. Voluntary int64 `json:"voluntary"`
  98. Involuntary int64 `json:"involuntary"`
  99. }
  100. type PageFaultsStat struct {
  101. MinorFaults uint64 `json:"minorFaults"`
  102. MajorFaults uint64 `json:"majorFaults"`
  103. ChildMinorFaults uint64 `json:"childMinorFaults"`
  104. ChildMajorFaults uint64 `json:"childMajorFaults"`
  105. }
  106. // Resource limit constants are from /usr/include/x86_64-linux-gnu/bits/resource.h
  107. // from libc6-dev package in Ubuntu 16.10
  108. const (
  109. RLIMIT_CPU int32 = 0
  110. RLIMIT_FSIZE int32 = 1
  111. RLIMIT_DATA int32 = 2
  112. RLIMIT_STACK int32 = 3
  113. RLIMIT_CORE int32 = 4
  114. RLIMIT_RSS int32 = 5
  115. RLIMIT_NPROC int32 = 6
  116. RLIMIT_NOFILE int32 = 7
  117. RLIMIT_MEMLOCK int32 = 8
  118. RLIMIT_AS int32 = 9
  119. RLIMIT_LOCKS int32 = 10
  120. RLIMIT_SIGPENDING int32 = 11
  121. RLIMIT_MSGQUEUE int32 = 12
  122. RLIMIT_NICE int32 = 13
  123. RLIMIT_RTPRIO int32 = 14
  124. RLIMIT_RTTIME int32 = 15
  125. )
  126. func (p Process) String() string {
  127. s, _ := json.Marshal(p)
  128. return string(s)
  129. }
  130. func (o OpenFilesStat) String() string {
  131. s, _ := json.Marshal(o)
  132. return string(s)
  133. }
  134. func (m MemoryInfoStat) String() string {
  135. s, _ := json.Marshal(m)
  136. return string(s)
  137. }
  138. func (r RlimitStat) String() string {
  139. s, _ := json.Marshal(r)
  140. return string(s)
  141. }
  142. func (i IOCountersStat) String() string {
  143. s, _ := json.Marshal(i)
  144. return string(s)
  145. }
  146. func (p NumCtxSwitchesStat) String() string {
  147. s, _ := json.Marshal(p)
  148. return string(s)
  149. }
  150. // Pids returns a slice of process ID list which are running now.
  151. func Pids() ([]int32, error) {
  152. return PidsWithContext(context.Background())
  153. }
  154. func PidsWithContext(ctx context.Context) ([]int32, error) {
  155. pids, err := pidsWithContext(ctx)
  156. sort.Slice(pids, func(i, j int) bool { return pids[i] < pids[j] })
  157. return pids, err
  158. }
  159. // Processes returns a slice of pointers to Process structs for all
  160. // currently running processes.
  161. func Processes() ([]*Process, error) {
  162. return ProcessesWithContext(context.Background())
  163. }
  164. // NewProcess creates a new Process instance, it only stores the pid and
  165. // checks that the process exists. Other method on Process can be used
  166. // to get more information about the process. An error will be returned
  167. // if the process does not exist.
  168. func NewProcess(pid int32) (*Process, error) {
  169. return NewProcessWithContext(context.Background(), pid)
  170. }
  171. func NewProcessWithContext(ctx context.Context, pid int32) (*Process, error) {
  172. p := &Process{
  173. Pid: pid,
  174. }
  175. exists, err := PidExistsWithContext(ctx, pid)
  176. if err != nil {
  177. return p, err
  178. }
  179. if !exists {
  180. return p, ErrorProcessNotRunning
  181. }
  182. p.CreateTimeWithContext(ctx)
  183. return p, nil
  184. }
  185. func PidExists(pid int32) (bool, error) {
  186. return PidExistsWithContext(context.Background(), pid)
  187. }
  188. // Background returns true if the process is in background, false otherwise.
  189. func (p *Process) Background() (bool, error) {
  190. return p.BackgroundWithContext(context.Background())
  191. }
  192. func (p *Process) BackgroundWithContext(ctx context.Context) (bool, error) {
  193. fg, err := p.ForegroundWithContext(ctx)
  194. if err != nil {
  195. return false, err
  196. }
  197. return !fg, err
  198. }
  199. // If interval is 0, return difference from last call(non-blocking).
  200. // If interval > 0, wait interval sec and return difference between start and end.
  201. func (p *Process) Percent(interval time.Duration) (float64, error) {
  202. return p.PercentWithContext(context.Background(), interval)
  203. }
  204. func (p *Process) PercentWithContext(ctx context.Context, interval time.Duration) (float64, error) {
  205. cpuTimes, err := p.TimesWithContext(ctx)
  206. if err != nil {
  207. return 0, err
  208. }
  209. now := time.Now()
  210. if interval > 0 {
  211. p.lastCPUTimes = cpuTimes
  212. p.lastCPUTime = now
  213. if err := common.Sleep(ctx, interval); err != nil {
  214. return 0, err
  215. }
  216. cpuTimes, err = p.TimesWithContext(ctx)
  217. now = time.Now()
  218. if err != nil {
  219. return 0, err
  220. }
  221. } else {
  222. if p.lastCPUTimes == nil {
  223. // invoked first time
  224. p.lastCPUTimes = cpuTimes
  225. p.lastCPUTime = now
  226. return 0, nil
  227. }
  228. }
  229. numcpu := runtime.NumCPU()
  230. delta := (now.Sub(p.lastCPUTime).Seconds()) * float64(numcpu)
  231. ret := calculatePercent(p.lastCPUTimes, cpuTimes, delta, numcpu)
  232. p.lastCPUTimes = cpuTimes
  233. p.lastCPUTime = now
  234. return ret, nil
  235. }
  236. // IsRunning returns whether the process is still running or not.
  237. func (p *Process) IsRunning() (bool, error) {
  238. return p.IsRunningWithContext(context.Background())
  239. }
  240. func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
  241. createTime, err := p.CreateTimeWithContext(ctx)
  242. if err != nil {
  243. return false, err
  244. }
  245. p2, err := NewProcessWithContext(ctx, p.Pid)
  246. if errors.Is(err, ErrorProcessNotRunning) {
  247. return false, nil
  248. }
  249. createTime2, err := p2.CreateTimeWithContext(ctx)
  250. if err != nil {
  251. return false, err
  252. }
  253. return createTime == createTime2, nil
  254. }
  255. // CreateTime returns created time of the process in milliseconds since the epoch, in UTC.
  256. func (p *Process) CreateTime() (int64, error) {
  257. return p.CreateTimeWithContext(context.Background())
  258. }
  259. func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
  260. if p.createTime != 0 {
  261. return p.createTime, nil
  262. }
  263. createTime, err := p.createTimeWithContext(ctx)
  264. p.createTime = createTime
  265. return p.createTime, err
  266. }
  267. func calculatePercent(t1, t2 *cpu.TimesStat, delta float64, numcpu int) float64 {
  268. if delta == 0 {
  269. return 0
  270. }
  271. delta_proc := t2.Total() - t1.Total()
  272. overall_percent := ((delta_proc / delta) * 100) * float64(numcpu)
  273. return overall_percent
  274. }
  275. // MemoryPercent returns how many percent of the total RAM this process uses
  276. func (p *Process) MemoryPercent() (float32, error) {
  277. return p.MemoryPercentWithContext(context.Background())
  278. }
  279. func (p *Process) MemoryPercentWithContext(ctx context.Context) (float32, error) {
  280. machineMemory, err := mem.VirtualMemoryWithContext(ctx)
  281. if err != nil {
  282. return 0, err
  283. }
  284. total := machineMemory.Total
  285. processMemory, err := p.MemoryInfoWithContext(ctx)
  286. if err != nil {
  287. return 0, err
  288. }
  289. used := processMemory.RSS
  290. return (100 * float32(used) / float32(total)), nil
  291. }
  292. // CPU_Percent returns how many percent of the CPU time this process uses
  293. func (p *Process) CPUPercent() (float64, error) {
  294. return p.CPUPercentWithContext(context.Background())
  295. }
  296. func (p *Process) CPUPercentWithContext(ctx context.Context) (float64, error) {
  297. crt_time, err := p.createTimeWithContext(ctx)
  298. if err != nil {
  299. return 0, err
  300. }
  301. cput, err := p.TimesWithContext(ctx)
  302. if err != nil {
  303. return 0, err
  304. }
  305. created := time.Unix(0, crt_time*int64(time.Millisecond))
  306. totalTime := time.Since(created).Seconds()
  307. if totalTime <= 0 {
  308. return 0, nil
  309. }
  310. return 100 * cput.Total() / totalTime, nil
  311. }
  312. // Groups returns all group IDs(include supplementary groups) of the process as a slice of the int
  313. func (p *Process) Groups() ([]int32, error) {
  314. return p.GroupsWithContext(context.Background())
  315. }
  316. // Ppid returns Parent Process ID of the process.
  317. func (p *Process) Ppid() (int32, error) {
  318. return p.PpidWithContext(context.Background())
  319. }
  320. // Name returns name of the process.
  321. func (p *Process) Name() (string, error) {
  322. return p.NameWithContext(context.Background())
  323. }
  324. // Exe returns executable path of the process.
  325. func (p *Process) Exe() (string, error) {
  326. return p.ExeWithContext(context.Background())
  327. }
  328. // Cmdline returns the command line arguments of the process as a string with
  329. // each argument separated by 0x20 ascii character.
  330. func (p *Process) Cmdline() (string, error) {
  331. return p.CmdlineWithContext(context.Background())
  332. }
  333. // CmdlineSlice returns the command line arguments of the process as a slice with each
  334. // element being an argument.
  335. func (p *Process) CmdlineSlice() ([]string, error) {
  336. return p.CmdlineSliceWithContext(context.Background())
  337. }
  338. // Cwd returns current working directory of the process.
  339. func (p *Process) Cwd() (string, error) {
  340. return p.CwdWithContext(context.Background())
  341. }
  342. // Parent returns parent Process of the process.
  343. func (p *Process) Parent() (*Process, error) {
  344. return p.ParentWithContext(context.Background())
  345. }
  346. // ParentWithContext returns parent Process of the process.
  347. func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {
  348. ppid, err := p.PpidWithContext(ctx)
  349. if err != nil {
  350. return nil, err
  351. }
  352. return NewProcessWithContext(ctx, ppid)
  353. }
  354. // Status returns the process status.
  355. // Return value could be one of these.
  356. // R: Running S: Sleep T: Stop I: Idle
  357. // Z: Zombie W: Wait L: Lock
  358. // The character is same within all supported platforms.
  359. func (p *Process) Status() ([]string, error) {
  360. return p.StatusWithContext(context.Background())
  361. }
  362. // Foreground returns true if the process is in foreground, false otherwise.
  363. func (p *Process) Foreground() (bool, error) {
  364. return p.ForegroundWithContext(context.Background())
  365. }
  366. // Uids returns user ids of the process as a slice of the int
  367. func (p *Process) Uids() ([]int32, error) {
  368. return p.UidsWithContext(context.Background())
  369. }
  370. // Gids returns group ids of the process as a slice of the int
  371. func (p *Process) Gids() ([]int32, error) {
  372. return p.GidsWithContext(context.Background())
  373. }
  374. // Terminal returns a terminal which is associated with the process.
  375. func (p *Process) Terminal() (string, error) {
  376. return p.TerminalWithContext(context.Background())
  377. }
  378. // Nice returns a nice value (priority).
  379. func (p *Process) Nice() (int32, error) {
  380. return p.NiceWithContext(context.Background())
  381. }
  382. // IOnice returns process I/O nice value (priority).
  383. func (p *Process) IOnice() (int32, error) {
  384. return p.IOniceWithContext(context.Background())
  385. }
  386. // Rlimit returns Resource Limits.
  387. func (p *Process) Rlimit() ([]RlimitStat, error) {
  388. return p.RlimitWithContext(context.Background())
  389. }
  390. // RlimitUsage returns Resource Limits.
  391. // If gatherUsed is true, the currently used value will be gathered and added
  392. // to the resulting RlimitStat.
  393. func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) {
  394. return p.RlimitUsageWithContext(context.Background(), gatherUsed)
  395. }
  396. // IOCounters returns IO Counters.
  397. func (p *Process) IOCounters() (*IOCountersStat, error) {
  398. return p.IOCountersWithContext(context.Background())
  399. }
  400. // NumCtxSwitches returns the number of the context switches of the process.
  401. func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
  402. return p.NumCtxSwitchesWithContext(context.Background())
  403. }
  404. // NumFDs returns the number of File Descriptors used by the process.
  405. func (p *Process) NumFDs() (int32, error) {
  406. return p.NumFDsWithContext(context.Background())
  407. }
  408. // NumThreads returns the number of threads used by the process.
  409. func (p *Process) NumThreads() (int32, error) {
  410. return p.NumThreadsWithContext(context.Background())
  411. }
  412. func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) {
  413. return p.ThreadsWithContext(context.Background())
  414. }
  415. // Times returns CPU times of the process.
  416. func (p *Process) Times() (*cpu.TimesStat, error) {
  417. return p.TimesWithContext(context.Background())
  418. }
  419. // CPUAffinity returns CPU affinity of the process.
  420. func (p *Process) CPUAffinity() ([]int32, error) {
  421. return p.CPUAffinityWithContext(context.Background())
  422. }
  423. // MemoryInfo returns generic process memory information,
  424. // such as RSS and VMS.
  425. func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
  426. return p.MemoryInfoWithContext(context.Background())
  427. }
  428. // MemoryInfoEx returns platform-specific process memory information.
  429. func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
  430. return p.MemoryInfoExWithContext(context.Background())
  431. }
  432. // PageFaultsInfo returns the process's page fault counters.
  433. func (p *Process) PageFaults() (*PageFaultsStat, error) {
  434. return p.PageFaultsWithContext(context.Background())
  435. }
  436. // Children returns the children of the process represented as a slice
  437. // of pointers to Process type.
  438. func (p *Process) Children() ([]*Process, error) {
  439. return p.ChildrenWithContext(context.Background())
  440. }
  441. // OpenFiles returns a slice of OpenFilesStat opend by the process.
  442. // OpenFilesStat includes a file path and file descriptor.
  443. func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
  444. return p.OpenFilesWithContext(context.Background())
  445. }
  446. // Connections returns a slice of net.ConnectionStat used by the process.
  447. // This returns all kind of the connection. This means TCP, UDP or UNIX.
  448. func (p *Process) Connections() ([]net.ConnectionStat, error) {
  449. return p.ConnectionsWithContext(context.Background())
  450. }
  451. // Connections returns a slice of net.ConnectionStat used by the process at most `max`.
  452. func (p *Process) ConnectionsMax(max int) ([]net.ConnectionStat, error) {
  453. return p.ConnectionsMaxWithContext(context.Background(), max)
  454. }
  455. // MemoryMaps get memory maps from /proc/(pid)/smaps
  456. func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
  457. return p.MemoryMapsWithContext(context.Background(), grouped)
  458. }
  459. // Tgid returns thread group id of the process.
  460. func (p *Process) Tgid() (int32, error) {
  461. return p.TgidWithContext(context.Background())
  462. }
  463. // SendSignal sends a unix.Signal to the process.
  464. func (p *Process) SendSignal(sig Signal) error {
  465. return p.SendSignalWithContext(context.Background(), sig)
  466. }
  467. // Suspend sends SIGSTOP to the process.
  468. func (p *Process) Suspend() error {
  469. return p.SuspendWithContext(context.Background())
  470. }
  471. // Resume sends SIGCONT to the process.
  472. func (p *Process) Resume() error {
  473. return p.ResumeWithContext(context.Background())
  474. }
  475. // Terminate sends SIGTERM to the process.
  476. func (p *Process) Terminate() error {
  477. return p.TerminateWithContext(context.Background())
  478. }
  479. // Kill sends SIGKILL to the process.
  480. func (p *Process) Kill() error {
  481. return p.KillWithContext(context.Background())
  482. }
  483. // Username returns a username of the process.
  484. func (p *Process) Username() (string, error) {
  485. return p.UsernameWithContext(context.Background())
  486. }
  487. // Environ returns the environment variables of the process.
  488. func (p *Process) Environ() ([]string, error) {
  489. return p.EnvironWithContext(context.Background())
  490. }
  491. // convertStatusChar as reported by the ps command across different platforms.
  492. func convertStatusChar(letter string) string {
  493. // Sources
  494. // Darwin: http://www.mywebuniversity.com/Man_Pages/Darwin/man_ps.html
  495. // FreeBSD: https://www.freebsd.org/cgi/man.cgi?ps
  496. // Linux https://man7.org/linux/man-pages/man1/ps.1.html
  497. // OpenBSD: https://man.openbsd.org/ps.1#state
  498. // Solaris: https://github.com/collectd/collectd/blob/1da3305c10c8ff9a63081284cf3d4bb0f6daffd8/src/processes.c#L2115
  499. switch letter {
  500. case "A":
  501. return Daemon
  502. case "D", "U":
  503. return Blocked
  504. case "E":
  505. return Detached
  506. case "I":
  507. return Idle
  508. case "L":
  509. return Lock
  510. case "O":
  511. return Orphan
  512. case "R":
  513. return Running
  514. case "S":
  515. return Sleep
  516. case "T", "t":
  517. // "t" is used by Linux to signal stopped by the debugger during tracing
  518. return Stop
  519. case "W":
  520. return Wait
  521. case "Y":
  522. return System
  523. case "Z":
  524. return Zombie
  525. default:
  526. return UnknownState
  527. }
  528. }