...
1 package system
2
3 import (
4 "fmt"
5 "os"
6 "path/filepath"
7 "strconv"
8 "strings"
9 )
10
11
12 type State rune
13
14 const (
15 Dead State = 'X'
16 DiskSleep State = 'D'
17 Running State = 'R'
18 Sleeping State = 'S'
19 Stopped State = 'T'
20 TracingStop State = 't'
21 Zombie State = 'Z'
22 Parked State = 'P'
23 Idle State = 'I'
24 )
25
26
27
28 func (s State) String() string {
29 switch s {
30 case Dead:
31 return "dead"
32 case DiskSleep:
33 return "disk sleep"
34 case Running:
35 return "running"
36 case Sleeping:
37 return "sleeping"
38 case Stopped:
39 return "stopped"
40 case TracingStop:
41 return "tracing stop"
42 case Zombie:
43 return "zombie"
44 case Parked:
45 return "parked"
46 case Idle:
47 return "idle"
48 default:
49 return fmt.Sprintf("unknown (%c)", s)
50 }
51 }
52
53
54
55
56 type Stat_t struct {
57
58 Name string
59
60
61 State State
62
63
64
65 StartTime uint64
66 }
67
68
69 func Stat(pid int) (stat Stat_t, err error) {
70 bytes, err := os.ReadFile(filepath.Join("/proc", strconv.Itoa(pid), "stat"))
71 if err != nil {
72 return stat, err
73 }
74 return parseStat(string(bytes))
75 }
76
77 func parseStat(data string) (stat Stat_t, err error) {
78
79
80
81
82
83
84
85
86
87
88
89
90
91 const minAfterName = 20*2 + 1
92
93 first := strings.IndexByte(data, '(')
94 if first < 0 || first+minAfterName >= len(data) {
95 return stat, fmt.Errorf("invalid stat data (no comm or too short): %q", data)
96 }
97
98 last := strings.LastIndexByte(data, ')')
99 if last <= first || last+minAfterName >= len(data) {
100 return stat, fmt.Errorf("invalid stat data (no comm or too short): %q", data)
101 }
102
103 stat.Name = data[first+1 : last]
104
105
106 data = data[last+2:]
107 stat.State = State(data[0])
108
109
110 skipSpaces := 22 - 3
111 for first = 0; skipSpaces > 0 && first < len(data); first++ {
112 if data[first] == ' ' {
113 skipSpaces--
114 }
115 }
116
117 i := strings.IndexByte(data[first:], ' ')
118 if i < 0 {
119 return stat, fmt.Errorf("invalid stat data (too short): %q", data)
120 }
121 stat.StartTime, err = strconv.ParseUint(data[first:first+i], 10, 64)
122 if err != nil {
123 return stat, fmt.Errorf("invalid stat data (bad start time): %w", err)
124 }
125
126 return stat, nil
127 }
128
View as plain text