1 package process
2
3 import (
4 "context"
5 "encoding/json"
6 "errors"
7 "runtime"
8 "sort"
9 "sync"
10 "syscall"
11 "time"
12
13 "github.com/shirou/gopsutil/cpu"
14 "github.com/shirou/gopsutil/internal/common"
15 "github.com/shirou/gopsutil/mem"
16 "github.com/shirou/gopsutil/net"
17 )
18
19 var (
20 invoke common.Invoker = common.Invoke{}
21 ErrorNoChildren = errors.New("process does not have children")
22 ErrorProcessNotRunning = errors.New("process does not exist")
23 )
24
25 type Process struct {
26 Pid int32 `json:"pid"`
27 name string
28 status string
29 parent int32
30 parentMutex sync.RWMutex
31 numCtxSwitches *NumCtxSwitchesStat
32 uids []int32
33 gids []int32
34 groups []int32
35 numThreads int32
36 memInfo *MemoryInfoStat
37 sigInfo *SignalInfoStat
38 createTime int64
39
40 lastCPUTimes *cpu.TimesStat
41 lastCPUTime time.Time
42
43 tgid int32
44 }
45
46 type OpenFilesStat struct {
47 Path string `json:"path"`
48 Fd uint64 `json:"fd"`
49 }
50
51 type MemoryInfoStat struct {
52 RSS uint64 `json:"rss"`
53 VMS uint64 `json:"vms"`
54 HWM uint64 `json:"hwm"`
55 Data uint64 `json:"data"`
56 Stack uint64 `json:"stack"`
57 Locked uint64 `json:"locked"`
58 Swap uint64 `json:"swap"`
59 }
60
61 type SignalInfoStat struct {
62 PendingProcess uint64 `json:"pending_process"`
63 PendingThread uint64 `json:"pending_thread"`
64 Blocked uint64 `json:"blocked"`
65 Ignored uint64 `json:"ignored"`
66 Caught uint64 `json:"caught"`
67 }
68
69 type RlimitStat struct {
70 Resource int32 `json:"resource"`
71 Soft int32 `json:"soft"`
72 Hard int32 `json:"hard"`
73 Used uint64 `json:"used"`
74 }
75
76 type IOCountersStat struct {
77 ReadCount uint64 `json:"readCount"`
78 WriteCount uint64 `json:"writeCount"`
79 ReadBytes uint64 `json:"readBytes"`
80 WriteBytes uint64 `json:"writeBytes"`
81 }
82
83 type NumCtxSwitchesStat struct {
84 Voluntary int64 `json:"voluntary"`
85 Involuntary int64 `json:"involuntary"`
86 }
87
88 type PageFaultsStat struct {
89 MinorFaults uint64 `json:"minorFaults"`
90 MajorFaults uint64 `json:"majorFaults"`
91 ChildMinorFaults uint64 `json:"childMinorFaults"`
92 ChildMajorFaults uint64 `json:"childMajorFaults"`
93 }
94
95
96
97 const (
98 RLIMIT_CPU int32 = 0
99 RLIMIT_FSIZE int32 = 1
100 RLIMIT_DATA int32 = 2
101 RLIMIT_STACK int32 = 3
102 RLIMIT_CORE int32 = 4
103 RLIMIT_RSS int32 = 5
104 RLIMIT_NPROC int32 = 6
105 RLIMIT_NOFILE int32 = 7
106 RLIMIT_MEMLOCK int32 = 8
107 RLIMIT_AS int32 = 9
108 RLIMIT_LOCKS int32 = 10
109 RLIMIT_SIGPENDING int32 = 11
110 RLIMIT_MSGQUEUE int32 = 12
111 RLIMIT_NICE int32 = 13
112 RLIMIT_RTPRIO int32 = 14
113 RLIMIT_RTTIME int32 = 15
114 )
115
116 func (p Process) String() string {
117 s, _ := json.Marshal(p)
118 return string(s)
119 }
120
121 func (o OpenFilesStat) String() string {
122 s, _ := json.Marshal(o)
123 return string(s)
124 }
125
126 func (m MemoryInfoStat) String() string {
127 s, _ := json.Marshal(m)
128 return string(s)
129 }
130
131 func (r RlimitStat) String() string {
132 s, _ := json.Marshal(r)
133 return string(s)
134 }
135
136 func (i IOCountersStat) String() string {
137 s, _ := json.Marshal(i)
138 return string(s)
139 }
140
141 func (p NumCtxSwitchesStat) String() string {
142 s, _ := json.Marshal(p)
143 return string(s)
144 }
145
146
147 func Pids() ([]int32, error) {
148 return PidsWithContext(context.Background())
149 }
150
151 func PidsWithContext(ctx context.Context) ([]int32, error) {
152 pids, err := pidsWithContext(ctx)
153 sort.Slice(pids, func(i, j int) bool { return pids[i] < pids[j] })
154 return pids, err
155 }
156
157
158
159 func Processes() ([]*Process, error) {
160 return ProcessesWithContext(context.Background())
161 }
162
163
164
165
166
167 func NewProcess(pid int32) (*Process, error) {
168 return NewProcessWithContext(context.Background(), pid)
169 }
170
171 func NewProcessWithContext(ctx context.Context, pid int32) (*Process, error) {
172 p := &Process{
173 Pid: pid,
174 }
175
176 exists, err := PidExistsWithContext(ctx, pid)
177 if err != nil {
178 return p, err
179 }
180 if !exists {
181 return p, ErrorProcessNotRunning
182 }
183 p.CreateTimeWithContext(ctx)
184 return p, nil
185 }
186
187 func PidExists(pid int32) (bool, error) {
188 return PidExistsWithContext(context.Background(), pid)
189 }
190
191
192 func (p *Process) Background() (bool, error) {
193 return p.BackgroundWithContext(context.Background())
194 }
195
196 func (p *Process) BackgroundWithContext(ctx context.Context) (bool, error) {
197 fg, err := p.ForegroundWithContext(ctx)
198 if err != nil {
199 return false, err
200 }
201 return !fg, err
202 }
203
204
205
206 func (p *Process) Percent(interval time.Duration) (float64, error) {
207 return p.PercentWithContext(context.Background(), interval)
208 }
209
210 func (p *Process) PercentWithContext(ctx context.Context, interval time.Duration) (float64, error) {
211 cpuTimes, err := p.TimesWithContext(ctx)
212 if err != nil {
213 return 0, err
214 }
215 now := time.Now()
216
217 if interval > 0 {
218 p.lastCPUTimes = cpuTimes
219 p.lastCPUTime = now
220 if err := common.Sleep(ctx, interval); err != nil {
221 return 0, err
222 }
223 cpuTimes, err = p.TimesWithContext(ctx)
224 now = time.Now()
225 if err != nil {
226 return 0, err
227 }
228 } else {
229 if p.lastCPUTimes == nil {
230
231 p.lastCPUTimes = cpuTimes
232 p.lastCPUTime = now
233 return 0, nil
234 }
235 }
236
237 numcpu := runtime.NumCPU()
238 delta := (now.Sub(p.lastCPUTime).Seconds()) * float64(numcpu)
239 ret := calculatePercent(p.lastCPUTimes, cpuTimes, delta, numcpu)
240 p.lastCPUTimes = cpuTimes
241 p.lastCPUTime = now
242 return ret, nil
243 }
244
245
246 func (p *Process) IsRunning() (bool, error) {
247 return p.IsRunningWithContext(context.Background())
248 }
249
250 func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
251 createTime, err := p.CreateTimeWithContext(ctx)
252 if err != nil {
253 return false, err
254 }
255 p2, err := NewProcessWithContext(ctx, p.Pid)
256 if err == ErrorProcessNotRunning {
257 return false, nil
258 }
259 createTime2, err := p2.CreateTimeWithContext(ctx)
260 if err != nil {
261 return false, err
262 }
263 return createTime == createTime2, nil
264 }
265
266
267 func (p *Process) CreateTime() (int64, error) {
268 return p.CreateTimeWithContext(context.Background())
269 }
270
271 func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
272 if p.createTime != 0 {
273 return p.createTime, nil
274 }
275 createTime, err := p.createTimeWithContext(ctx)
276 p.createTime = createTime
277 return p.createTime, err
278 }
279
280 func calculatePercent(t1, t2 *cpu.TimesStat, delta float64, numcpu int) float64 {
281 if delta == 0 {
282 return 0
283 }
284 delta_proc := t2.Total() - t1.Total()
285 overall_percent := ((delta_proc / delta) * 100) * float64(numcpu)
286 return overall_percent
287 }
288
289
290 func (p *Process) MemoryPercent() (float32, error) {
291 return p.MemoryPercentWithContext(context.Background())
292 }
293
294 func (p *Process) MemoryPercentWithContext(ctx context.Context) (float32, error) {
295 machineMemory, err := mem.VirtualMemoryWithContext(ctx)
296 if err != nil {
297 return 0, err
298 }
299 total := machineMemory.Total
300
301 processMemory, err := p.MemoryInfoWithContext(ctx)
302 if err != nil {
303 return 0, err
304 }
305 used := processMemory.RSS
306
307 return (100 * float32(used) / float32(total)), nil
308 }
309
310
311 func (p *Process) CPUPercent() (float64, error) {
312 return p.CPUPercentWithContext(context.Background())
313 }
314
315 func (p *Process) CPUPercentWithContext(ctx context.Context) (float64, error) {
316 crt_time, err := p.createTimeWithContext(ctx)
317 if err != nil {
318 return 0, err
319 }
320
321 cput, err := p.TimesWithContext(ctx)
322 if err != nil {
323 return 0, err
324 }
325
326 created := time.Unix(0, crt_time*int64(time.Millisecond))
327 totalTime := time.Since(created).Seconds()
328 if totalTime <= 0 {
329 return 0, nil
330 }
331
332 return 100 * cput.Total() / totalTime, nil
333 }
334
335
336 func (p *Process) Groups() ([]int32, error) {
337 return p.GroupsWithContext(context.Background())
338 }
339
340
341 func (p *Process) Ppid() (int32, error) {
342 return p.PpidWithContext(context.Background())
343 }
344
345
346 func (p *Process) Name() (string, error) {
347 return p.NameWithContext(context.Background())
348 }
349
350
351 func (p *Process) Exe() (string, error) {
352 return p.ExeWithContext(context.Background())
353 }
354
355
356
357 func (p *Process) Cmdline() (string, error) {
358 return p.CmdlineWithContext(context.Background())
359 }
360
361
362
363 func (p *Process) CmdlineSlice() ([]string, error) {
364 return p.CmdlineSliceWithContext(context.Background())
365 }
366
367
368 func (p *Process) Cwd() (string, error) {
369 return p.CwdWithContext(context.Background())
370 }
371
372
373 func (p *Process) Parent() (*Process, error) {
374 return p.ParentWithContext(context.Background())
375 }
376
377
378
379
380
381
382 func (p *Process) Status() (string, error) {
383 return p.StatusWithContext(context.Background())
384 }
385
386
387 func (p *Process) Foreground() (bool, error) {
388 return p.ForegroundWithContext(context.Background())
389 }
390
391
392 func (p *Process) Uids() ([]int32, error) {
393 return p.UidsWithContext(context.Background())
394 }
395
396
397 func (p *Process) Gids() ([]int32, error) {
398 return p.GidsWithContext(context.Background())
399 }
400
401
402 func (p *Process) Terminal() (string, error) {
403 return p.TerminalWithContext(context.Background())
404 }
405
406
407 func (p *Process) Nice() (int32, error) {
408 return p.NiceWithContext(context.Background())
409 }
410
411
412 func (p *Process) IOnice() (int32, error) {
413 return p.IOniceWithContext(context.Background())
414 }
415
416
417 func (p *Process) Rlimit() ([]RlimitStat, error) {
418 return p.RlimitWithContext(context.Background())
419 }
420
421
422
423
424 func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) {
425 return p.RlimitUsageWithContext(context.Background(), gatherUsed)
426 }
427
428
429 func (p *Process) IOCounters() (*IOCountersStat, error) {
430 return p.IOCountersWithContext(context.Background())
431 }
432
433
434 func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
435 return p.NumCtxSwitchesWithContext(context.Background())
436 }
437
438
439 func (p *Process) NumFDs() (int32, error) {
440 return p.NumFDsWithContext(context.Background())
441 }
442
443
444 func (p *Process) NumThreads() (int32, error) {
445 return p.NumThreadsWithContext(context.Background())
446 }
447
448 func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) {
449 return p.ThreadsWithContext(context.Background())
450 }
451
452
453 func (p *Process) Times() (*cpu.TimesStat, error) {
454 return p.TimesWithContext(context.Background())
455 }
456
457
458 func (p *Process) CPUAffinity() ([]int32, error) {
459 return p.CPUAffinityWithContext(context.Background())
460 }
461
462
463
464 func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
465 return p.MemoryInfoWithContext(context.Background())
466 }
467
468
469 func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
470 return p.MemoryInfoExWithContext(context.Background())
471 }
472
473
474 func (p *Process) PageFaults() (*PageFaultsStat, error) {
475 return p.PageFaultsWithContext(context.Background())
476 }
477
478
479
480 func (p *Process) Children() ([]*Process, error) {
481 return p.ChildrenWithContext(context.Background())
482 }
483
484
485
486 func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
487 return p.OpenFilesWithContext(context.Background())
488 }
489
490
491
492 func (p *Process) Connections() ([]net.ConnectionStat, error) {
493 return p.ConnectionsWithContext(context.Background())
494 }
495
496
497 func (p *Process) ConnectionsMax(max int) ([]net.ConnectionStat, error) {
498 return p.ConnectionsMaxWithContext(context.Background(), max)
499 }
500
501
502 func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
503 return p.NetIOCountersWithContext(context.Background(), pernic)
504 }
505
506
507 func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
508 return p.MemoryMapsWithContext(context.Background(), grouped)
509 }
510
511
512 func (p *Process) Tgid() (int32, error) {
513 return p.TgidWithContext(context.Background())
514 }
515
516
517 func (p *Process) SendSignal(sig syscall.Signal) error {
518 return p.SendSignalWithContext(context.Background(), sig)
519 }
520
521
522 func (p *Process) Suspend() error {
523 return p.SuspendWithContext(context.Background())
524 }
525
526
527 func (p *Process) Resume() error {
528 return p.ResumeWithContext(context.Background())
529 }
530
531
532 func (p *Process) Terminate() error {
533 return p.TerminateWithContext(context.Background())
534 }
535
536
537 func (p *Process) Kill() error {
538 return p.KillWithContext(context.Background())
539 }
540
541
542 func (p *Process) Username() (string, error) {
543 return p.UsernameWithContext(context.Background())
544 }
545
546
547 func (p *Process) Environ() ([]string, error) {
548 return p.EnvironWithContext(context.Background())
549 }
550
View as plain text