@@ -9,6 +9,7 @@ package process
9
9
// #include <sys/errno.h>
10
10
// #include <sys/proc_info.h>
11
11
// #include <sys/sysctl.h>
12
+ // #include <mach/mach_time.h>
12
13
import "C"
13
14
14
15
import (
@@ -18,12 +19,18 @@ import (
18
19
"strings"
19
20
"syscall"
20
21
"unsafe"
22
+
23
+ "github.com/shirou/gopsutil/v3/cpu"
21
24
)
22
25
23
- var argMax int
26
+ var (
27
+ argMax int
28
+ timescaleToNanoSeconds float64
29
+ )
24
30
25
31
func init () {
26
32
argMax = getArgMax ()
33
+ timescaleToNanoSeconds = getTimeScaleToNanoSeconds ()
27
34
}
28
35
29
36
func getArgMax () int {
@@ -39,6 +46,14 @@ func getArgMax() int {
39
46
return 0
40
47
}
41
48
49
+ func getTimeScaleToNanoSeconds () float64 {
50
+ var timeBaseInfo C.struct_mach_timebase_info
51
+
52
+ C .mach_timebase_info (& timeBaseInfo )
53
+
54
+ return float64 (timeBaseInfo .numer ) / float64 (timeBaseInfo .denom )
55
+ }
56
+
42
57
func (p * Process ) ExeWithContext (ctx context.Context ) (string , error ) {
43
58
var c C.char // need a var for unsafe.Sizeof need a var
44
59
const bufsize = C .PROC_PIDPATHINFO_MAXSIZE * unsafe .Sizeof (c )
@@ -82,7 +97,7 @@ func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
82
97
return C .GoString (& vpi .pvi_cdir .vip_path [0 ]), err
83
98
}
84
99
85
- func procArgs (pid int32 ) (* []byte , int , error ) {
100
+ func procArgs (pid int32 ) ([]byte , int , error ) {
86
101
var (
87
102
mib = [... ]C.int {C .CTL_KERN , C .KERN_PROCARGS2 , C .int (pid )}
88
103
size C.size_t = C .ulong (argMax )
@@ -91,23 +106,27 @@ func procArgs(pid int32) (*[]byte, int, error) {
91
106
)
92
107
procargs := (* C .char )(C .malloc (C .ulong (argMax )))
93
108
defer C .free (unsafe .Pointer (procargs ))
94
- retval := C .sysctl (& mib [0 ], 3 , unsafe .Pointer (procargs ), & size , C .NULL , 0 )
109
+ retval , err := C .sysctl (& mib [0 ], 3 , unsafe .Pointer (procargs ), & size , C .NULL , 0 )
95
110
if retval == 0 {
96
111
C .memcpy (unsafe .Pointer (& nargs ), unsafe .Pointer (procargs ), C .sizeof_int )
97
112
result = C .GoBytes (unsafe .Pointer (procargs ), C .int (size ))
98
113
// fmt.Printf("size: %d %d\n%s\n", size, nargs, hex.Dump(result))
99
- return & result , int (nargs ), nil
114
+ return result , int (nargs ), nil
100
115
}
101
- return nil , 0 , fmt . Errorf ( "error: %d" , retval )
116
+ return nil , 0 , err
102
117
}
103
118
104
119
func (p * Process ) CmdlineSliceWithContext (ctx context.Context ) ([]string , error ) {
120
+ return p .cmdlineSliceWithContext (ctx , true )
121
+ }
122
+
123
+ func (p * Process ) cmdlineSliceWithContext (ctx context.Context , fallback bool ) ([]string , error ) {
105
124
pargs , nargs , err := procArgs (p .Pid )
106
125
if err != nil {
107
126
return nil , err
108
127
}
109
128
// The first bytes hold the nargs int, skip it.
110
- args := bytes .Split ((* pargs )[C .sizeof_int :], []byte {0 })
129
+ args := bytes .Split ((pargs )[C .sizeof_int :], []byte {0 })
111
130
var argStr string
112
131
// The first element is the actual binary/command path.
113
132
// command := args[0]
@@ -131,10 +150,70 @@ func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error)
131
150
return argSlice , err
132
151
}
133
152
153
+ // cmdNameWithContext returns the command name (including spaces) without any arguments
154
+ func (p * Process ) cmdNameWithContext (ctx context.Context ) (string , error ) {
155
+ r , err := p .cmdlineSliceWithContext (ctx , false )
156
+ if err != nil {
157
+ return "" , err
158
+ }
159
+
160
+ if len (r ) == 0 {
161
+ return "" , nil
162
+ }
163
+
164
+ return r [0 ], err
165
+ }
166
+
134
167
func (p * Process ) CmdlineWithContext (ctx context.Context ) (string , error ) {
135
168
r , err := p .CmdlineSliceWithContext (ctx )
136
169
if err != nil {
137
170
return "" , err
138
171
}
139
172
return strings .Join (r , " " ), err
140
173
}
174
+
175
+ func (p * Process ) NumThreadsWithContext (ctx context.Context ) (int32 , error ) {
176
+ const tiSize = C .sizeof_struct_proc_taskinfo
177
+ ti := (* C .struct_proc_taskinfo )(C .malloc (tiSize ))
178
+
179
+ _ , err := C .proc_pidinfo (C .int (p .Pid ), C .PROC_PIDTASKINFO , 0 , unsafe .Pointer (ti ), tiSize )
180
+ if err != nil {
181
+ return 0 , err
182
+ }
183
+
184
+ return int32 (ti .pti_threadnum ), nil
185
+ }
186
+
187
+ func (p * Process ) TimesWithContext (ctx context.Context ) (* cpu.TimesStat , error ) {
188
+ const tiSize = C .sizeof_struct_proc_taskinfo
189
+ ti := (* C .struct_proc_taskinfo )(C .malloc (tiSize ))
190
+
191
+ _ , err := C .proc_pidinfo (C .int (p .Pid ), C .PROC_PIDTASKINFO , 0 , unsafe .Pointer (ti ), tiSize )
192
+ if err != nil {
193
+ return nil , err
194
+ }
195
+
196
+ ret := & cpu.TimesStat {
197
+ CPU : "cpu" ,
198
+ User : float64 (ti .pti_total_user ) * timescaleToNanoSeconds / 1e9 ,
199
+ System : float64 (ti .pti_total_system ) * timescaleToNanoSeconds / 1e9 ,
200
+ }
201
+ return ret , nil
202
+ }
203
+
204
+ func (p * Process ) MemoryInfoWithContext (ctx context.Context ) (* MemoryInfoStat , error ) {
205
+ const tiSize = C .sizeof_struct_proc_taskinfo
206
+ ti := (* C .struct_proc_taskinfo )(C .malloc (tiSize ))
207
+
208
+ _ , err := C .proc_pidinfo (C .int (p .Pid ), C .PROC_PIDTASKINFO , 0 , unsafe .Pointer (ti ), tiSize )
209
+ if err != nil {
210
+ return nil , err
211
+ }
212
+
213
+ ret := & MemoryInfoStat {
214
+ RSS : uint64 (ti .pti_resident_size ),
215
+ VMS : uint64 (ti .pti_virtual_size ),
216
+ Swap : uint64 (ti .pti_pageins ),
217
+ }
218
+ return ret , nil
219
+ }
0 commit comments