OLD | NEW |
1 /* | 1 /* |
2 * $Id: _psutil_bsd.c 780 2010-11-10 18:42:47Z jloden $ | 2 * $Id: _psutil_bsd.c 1142 2011-10-05 18:45:49Z g.rodola $ |
| 3 * |
| 4 * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. |
| 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. |
3 * | 7 * |
4 * FreeBSD platform-specific module methods for _psutil_bsd | 8 * FreeBSD platform-specific module methods for _psutil_bsd |
5 */ | 9 */ |
6 | 10 |
7 #include <Python.h> | 11 #include <Python.h> |
8 #include <assert.h> | 12 #include <assert.h> |
9 #include <errno.h> | 13 #include <errno.h> |
10 #include <stdlib.h> | 14 #include <stdlib.h> |
11 #include <stdio.h> | 15 #include <stdio.h> |
12 #include <signal.h> | 16 #include <signal.h> |
13 #include <sys/types.h> | 17 #include <sys/types.h> |
14 #include <sys/sysctl.h> | 18 #include <sys/sysctl.h> |
15 #include <sys/param.h> | 19 #include <sys/param.h> |
16 #include <sys/user.h> | 20 #include <sys/user.h> |
17 #include <sys/proc.h> | 21 #include <sys/proc.h> |
18 #include <sys/vmmeter.h> /* needed for vmtotal struct */ | 22 #include <sys/vmmeter.h> /* needed for vmtotal struct */ |
| 23 #include <sys/mount.h> |
| 24 // network-related stuff |
| 25 #include <net/if.h> |
| 26 #include <net/if_dl.h> |
| 27 #include <net/route.h> |
19 | 28 |
20 #include "_psutil_bsd.h" | 29 #include "_psutil_bsd.h" |
| 30 #include "_psutil_common.h" |
21 #include "arch/bsd/process_info.h" | 31 #include "arch/bsd/process_info.h" |
22 | 32 |
23 /* | |
24 * define the psutil C module methods and initialize the module. | |
25 */ | |
26 static PyMethodDef | |
27 PsutilMethods[] = | |
28 { | |
29 // --- per-process functions | |
30 | 33 |
31 {"get_process_name", get_process_name, METH_VARARGS, | 34 // convert a timeval struct to a double |
32 "Return process name"}, | 35 #define TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) |
33 {"get_process_cmdline", get_process_cmdline, METH_VARARGS, | |
34 "Return process cmdline as a list of cmdline arguments"}, | |
35 {"get_process_ppid", get_process_ppid, METH_VARARGS, | |
36 "Return process ppid as an integer"}, | |
37 {"get_process_uid", get_process_uid, METH_VARARGS, | |
38 "Return process real user id as an integer"}, | |
39 {"get_process_gid", get_process_gid, METH_VARARGS, | |
40 "Return process real group id as an integer"}, | |
41 {"get_cpu_times", get_cpu_times, METH_VARARGS, | |
42 "Return tuple of user/kern time for the given PID"}, | |
43 {"get_process_create_time", get_process_create_time, METH_VARARGS, | |
44 "Return a float indicating the process create time expressed in " | |
45 "seconds since the epoch"}, | |
46 {"get_memory_info", get_memory_info, METH_VARARGS, | |
47 "Return a tuple of RSS/VMS memory information"}, | |
48 {"get_process_num_threads", get_process_num_threads, METH_VARARGS, | |
49 "Return number of threads used by process"}, | |
50 | |
51 | |
52 // --- system-related functions | |
53 | |
54 {"get_pid_list", get_pid_list, METH_VARARGS, | |
55 "Returns a list of PIDs currently running on the system"}, | |
56 {"get_num_cpus", get_num_cpus, METH_VARARGS, | |
57 "Return number of CPUs on the system"}, | |
58 {"get_total_phymem", get_total_phymem, METH_VARARGS, | |
59 "Return the total amount of physical memory, in bytes"}, | |
60 {"get_avail_phymem", get_avail_phymem, METH_VARARGS, | |
61 "Return the amount of available physical memory, in bytes"}, | |
62 {"get_total_virtmem", get_total_virtmem, METH_VARARGS, | |
63 "Return the total amount of virtual memory, in bytes"}, | |
64 {"get_avail_virtmem", get_avail_virtmem, METH_VARARGS, | |
65 "Return the amount of available virtual memory, in bytes"}, | |
66 {"get_system_cpu_times", get_system_cpu_times, METH_VARARGS, | |
67 "Return system cpu times as a tuple (user, system, nice, idle, irc)"}, | |
68 | |
69 {NULL, NULL, 0, NULL} | |
70 }; | |
71 | |
72 struct module_state { | |
73 PyObject *error; | |
74 }; | |
75 | |
76 #if PY_MAJOR_VERSION >= 3 | |
77 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) | |
78 #else | |
79 #define GETSTATE(m) (&_state) | |
80 static struct module_state _state; | |
81 #endif | |
82 | |
83 #if PY_MAJOR_VERSION >= 3 | |
84 | |
85 static int | |
86 psutil_bsd_traverse(PyObject *m, visitproc visit, void *arg) { | |
87 Py_VISIT(GETSTATE(m)->error); | |
88 return 0; | |
89 } | |
90 | |
91 static int | |
92 psutil_bsd_clear(PyObject *m) { | |
93 Py_CLEAR(GETSTATE(m)->error); | |
94 return 0; | |
95 } | |
96 | |
97 static struct PyModuleDef | |
98 moduledef = { | |
99 PyModuleDef_HEAD_INIT, | |
100 "psutil_bsd", | |
101 NULL, | |
102 sizeof(struct module_state), | |
103 PsutilMethods, | |
104 NULL, | |
105 psutil_bsd_traverse, | |
106 psutil_bsd_clear, | |
107 NULL | |
108 }; | |
109 | |
110 #define INITERROR return NULL | |
111 | |
112 PyObject * | |
113 PyInit__psutil_bsd(void) | |
114 | |
115 #else | |
116 #define INITERROR return | |
117 | |
118 void init_psutil_bsd(void) | |
119 #endif | |
120 { | |
121 #if PY_MAJOR_VERSION >= 3 | |
122 PyObject *module = PyModule_Create(&moduledef); | |
123 #else | |
124 PyObject *module = Py_InitModule("_psutil_bsd", PsutilMethods); | |
125 #endif | |
126 if (module == NULL) { | |
127 INITERROR; | |
128 } | |
129 struct module_state *st = GETSTATE(module); | |
130 | |
131 st->error = PyErr_NewException("_psutil_bsd.Error", NULL, NULL); | |
132 if (st->error == NULL) { | |
133 Py_DECREF(module); | |
134 INITERROR; | |
135 } | |
136 #if PY_MAJOR_VERSION >= 3 | |
137 return module; | |
138 #endif | |
139 } | |
140 | 36 |
141 | 37 |
142 /* | 38 /* |
143 * Utility function which fills a kinfo_proc struct based on process pid | 39 * Utility function which fills a kinfo_proc struct based on process pid |
144 */ | 40 */ |
145 static int | 41 static int |
146 get_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) | 42 get_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) |
147 { | 43 { |
148 int mib[4]; | 44 int mib[4]; |
149 size_t size; | 45 size_t size; |
150 mib[0] = CTL_KERN; | 46 mib[0] = CTL_KERN; |
151 mib[1] = KERN_PROC; | 47 mib[1] = KERN_PROC; |
152 mib[2] = KERN_PROC_PID; | 48 mib[2] = KERN_PROC_PID; |
153 mib[3] = pid; | 49 mib[3] = pid; |
154 | 50 |
155 size = sizeof(struct kinfo_proc); | 51 size = sizeof(struct kinfo_proc); |
156 | 52 |
157 if (sysctl((int*)mib, 4, proc, &size, NULL, 0) == -1) { | 53 if (sysctl((int*)mib, 4, proc, &size, NULL, 0) == -1) { |
158 PyErr_SetFromErrno(PyExc_OSError); | 54 PyErr_SetFromErrno(PyExc_OSError); |
159 return -1; | 55 return -1; |
160 } | 56 } |
161 | 57 |
162 /* | 58 /* |
163 * sysctl stores 0 in the size if we can't find the process information. | 59 * sysctl stores 0 in the size if we can't find the process information. |
164 * Set errno to ESRCH which will be translated in NoSuchProcess later on. | |
165 */ | 60 */ |
166 if (size == 0) { | 61 if (size == 0) { |
167 errno = ESRCH; | 62 NoSuchProcess(); |
168 PyErr_SetFromErrno(PyExc_OSError); | |
169 return -1; | 63 return -1; |
170 } | 64 } |
171 return 0; | 65 return 0; |
172 } | 66 } |
173 | 67 |
174 | 68 |
175 /* | 69 /* |
176 * Return a Python list of all the PIDs running on the system. | 70 * Return a Python list of all the PIDs running on the system. |
177 */ | 71 */ |
178 static PyObject* | 72 static PyObject* |
(...skipping 21 matching lines...) Expand all Loading... |
200 proclist++; | 94 proclist++; |
201 } | 95 } |
202 free(orig_address); | 96 free(orig_address); |
203 } | 97 } |
204 | 98 |
205 return retlist; | 99 return retlist; |
206 } | 100 } |
207 | 101 |
208 | 102 |
209 /* | 103 /* |
| 104 * Return a Python float indicating the system boot time expressed in |
| 105 * seconds since the epoch. |
| 106 */ |
| 107 static PyObject* |
| 108 get_system_boot_time(PyObject* self, PyObject* args) |
| 109 { |
| 110 /* fetch sysctl "kern.boottime" */ |
| 111 static int request[2] = { CTL_KERN, KERN_BOOTTIME }; |
| 112 struct timeval result; |
| 113 size_t result_len = sizeof result; |
| 114 time_t boot_time = 0; |
| 115 |
| 116 if (sysctl(request, 2, &result, &result_len, NULL, 0) == -1) { |
| 117 PyErr_SetFromErrno(0); |
| 118 return NULL; |
| 119 } |
| 120 boot_time = result.tv_sec; |
| 121 return Py_BuildValue("f", (float)boot_time); |
| 122 } |
| 123 |
| 124 |
| 125 /* |
210 * Return process name from kinfo_proc as a Python string. | 126 * Return process name from kinfo_proc as a Python string. |
211 */ | 127 */ |
212 static PyObject* | 128 static PyObject* |
213 get_process_name(PyObject* self, PyObject* args) | 129 get_process_name(PyObject* self, PyObject* args) |
214 { | 130 { |
215 long pid; | 131 long pid; |
216 struct kinfo_proc kp; | 132 struct kinfo_proc kp; |
217 if (! PyArg_ParseTuple(args, "l", &pid)) { | 133 if (! PyArg_ParseTuple(args, "l", &pid)) { |
218 return NULL; | 134 return NULL; |
219 } | 135 } |
220 if (get_kinfo_proc(pid, &kp) == -1) { | 136 if (get_kinfo_proc(pid, &kp) == -1) { |
221 return NULL; | 137 return NULL; |
222 } | 138 } |
223 return Py_BuildValue("s", kp.ki_comm); | 139 return Py_BuildValue("s", kp.ki_comm); |
224 } | 140 } |
225 | 141 |
226 | 142 |
227 /* | 143 /* |
| 144 * Return process pathname executable. |
| 145 * Thanks to Robert N. M. Watson: |
| 146 * http://fxr.googlebit.com/source/usr.bin/procstat/procstat_bin.c?v=8-CURRENT |
| 147 */ |
| 148 static PyObject* |
| 149 get_process_exe(PyObject* self, PyObject* args) |
| 150 { |
| 151 long pid; |
| 152 char pathname[PATH_MAX]; |
| 153 int error; |
| 154 int mib[4]; |
| 155 size_t size; |
| 156 |
| 157 if (! PyArg_ParseTuple(args, "l", &pid)) { |
| 158 return NULL; |
| 159 } |
| 160 |
| 161 mib[0] = CTL_KERN; |
| 162 mib[1] = KERN_PROC; |
| 163 mib[2] = KERN_PROC_PATHNAME; |
| 164 mib[3] = pid; |
| 165 |
| 166 size = sizeof(pathname); |
| 167 error = sysctl(mib, 4, pathname, &size, NULL, 0); |
| 168 if (error == -1) { |
| 169 PyErr_SetFromErrno(PyExc_OSError); |
| 170 return NULL; |
| 171 } |
| 172 if (size == 0 || strlen(pathname) == 0) { |
| 173 if (pid_exists(pid) == 0) { |
| 174 return NoSuchProcess(); |
| 175 } |
| 176 else { |
| 177 strcpy(pathname, ""); |
| 178 } |
| 179 } |
| 180 return Py_BuildValue("s", pathname); |
| 181 } |
| 182 |
| 183 |
| 184 /* |
228 * Return process cmdline as a Python list of cmdline arguments. | 185 * Return process cmdline as a Python list of cmdline arguments. |
229 */ | 186 */ |
230 static PyObject* | 187 static PyObject* |
231 get_process_cmdline(PyObject* self, PyObject* args) | 188 get_process_cmdline(PyObject* self, PyObject* args) |
232 { | 189 { |
233 long pid; | 190 long pid; |
234 PyObject* arglist = NULL; | 191 PyObject* arglist = NULL; |
235 | 192 |
236 if (! PyArg_ParseTuple(args, "l", &pid)) { | 193 if (! PyArg_ParseTuple(args, "l", &pid)) { |
237 return NULL; | 194 return NULL; |
(...skipping 23 matching lines...) Expand all Loading... |
261 return NULL; | 218 return NULL; |
262 } | 219 } |
263 if (get_kinfo_proc(pid, &kp) == -1) { | 220 if (get_kinfo_proc(pid, &kp) == -1) { |
264 return NULL; | 221 return NULL; |
265 } | 222 } |
266 return Py_BuildValue("l", (long)kp.ki_ppid); | 223 return Py_BuildValue("l", (long)kp.ki_ppid); |
267 } | 224 } |
268 | 225 |
269 | 226 |
270 /* | 227 /* |
271 * Return process real uid from kinfo_proc as a Python integer. | 228 * Return process status as a Python integer. |
272 */ | 229 */ |
273 static PyObject* | 230 static PyObject* |
274 get_process_uid(PyObject* self, PyObject* args) | 231 get_process_status(PyObject* self, PyObject* args) |
275 { | 232 { |
276 long pid; | 233 long pid; |
277 struct kinfo_proc kp; | 234 struct kinfo_proc kp; |
| 235 if (! PyArg_ParseTuple(args, "l", &pid)) { |
| 236 return NULL; |
| 237 } |
| 238 if (get_kinfo_proc(pid, &kp) == -1) { |
| 239 return NULL; |
| 240 } |
| 241 return Py_BuildValue("i", (int)kp.ki_stat); |
| 242 } |
| 243 |
| 244 |
| 245 /* |
| 246 * Return process real, effective and saved user ids from kinfo_proc |
| 247 * as a Python tuple. |
| 248 */ |
| 249 static PyObject* |
| 250 get_process_uids(PyObject* self, PyObject* args) |
| 251 { |
| 252 long pid; |
| 253 struct kinfo_proc kp; |
278 if (! PyArg_ParseTuple(args, "l", &pid)) { | 254 if (! PyArg_ParseTuple(args, "l", &pid)) { |
279 return NULL; | 255 return NULL; |
280 } | 256 } |
281 if (get_kinfo_proc(pid, &kp) == -1) { | 257 if (get_kinfo_proc(pid, &kp) == -1) { |
282 return NULL; | 258 return NULL; |
283 } | 259 } |
284 return Py_BuildValue("l", (long)kp.ki_ruid); | 260 return Py_BuildValue("lll", (long)kp.ki_ruid, |
| 261 (long)kp.ki_uid, |
| 262 (long)kp.ki_svuid); |
285 } | 263 } |
286 | 264 |
287 | 265 |
288 /* | 266 /* |
289 * Return process real group id from ki_comm as a Python integer. | 267 * Return process real, effective and saved group ids from kinfo_proc |
| 268 * as a Python tuple. |
290 */ | 269 */ |
291 static PyObject* | 270 static PyObject* |
292 get_process_gid(PyObject* self, PyObject* args) | 271 get_process_gids(PyObject* self, PyObject* args) |
293 { | 272 { |
294 long pid; | 273 long pid; |
295 struct kinfo_proc kp; | 274 struct kinfo_proc kp; |
296 if (! PyArg_ParseTuple(args, "l", &pid)) { | 275 if (! PyArg_ParseTuple(args, "l", &pid)) { |
297 return NULL; | 276 return NULL; |
298 } | 277 } |
299 if (get_kinfo_proc(pid, &kp) == -1) { | 278 if (get_kinfo_proc(pid, &kp) == -1) { |
300 return NULL; | 279 return NULL; |
301 } | 280 } |
302 return Py_BuildValue("l", (long)kp.ki_rgid); | 281 return Py_BuildValue("lll", (long)kp.ki_rgid, |
| 282 (long)kp.ki_groups[0], |
| 283 (long)kp.ki_svuid); |
303 } | 284 } |
304 | 285 |
305 | 286 |
| 287 /* |
| 288 * Return process real, effective and saved group ids from kinfo_proc |
| 289 * as a Python tuple. |
| 290 */ |
| 291 static PyObject* |
| 292 get_process_tty_nr(PyObject* self, PyObject* args) |
| 293 { |
| 294 long pid; |
| 295 struct kinfo_proc kp; |
| 296 if (! PyArg_ParseTuple(args, "l", &pid)) { |
| 297 return NULL; |
| 298 } |
| 299 if (get_kinfo_proc(pid, &kp) == -1) { |
| 300 return NULL; |
| 301 } |
| 302 return Py_BuildValue("i", kp.ki_tdev); |
| 303 } |
| 304 |
| 305 |
306 /* | 306 /* |
307 * Return number of threads used by process as a Python integer. | 307 * Return number of threads used by process as a Python integer. |
308 */ | 308 */ |
309 static PyObject* | 309 static PyObject* |
310 get_process_num_threads(PyObject* self, PyObject* args) | 310 get_process_num_threads(PyObject* self, PyObject* args) |
311 { | 311 { |
312 long pid; | 312 long pid; |
313 struct kinfo_proc kp; | 313 struct kinfo_proc kp; |
314 if (! PyArg_ParseTuple(args, "l", &pid)) { | 314 if (! PyArg_ParseTuple(args, "l", &pid)) { |
315 return NULL; | 315 return NULL; |
316 } | 316 } |
317 if (get_kinfo_proc(pid, &kp) == -1) { | 317 if (get_kinfo_proc(pid, &kp) == -1) { |
318 return NULL; | 318 return NULL; |
319 } | 319 } |
320 return Py_BuildValue("l", (long)kp.ki_numthreads); | 320 return Py_BuildValue("l", (long)kp.ki_numthreads); |
321 } | 321 } |
322 | 322 |
323 | 323 |
| 324 /* |
| 325 * Retrieves all threads used by process returning a list of tuples |
| 326 * including thread id, user time and system time. |
| 327 * Thanks to Robert N. M. Watson: |
| 328 * http://fxr.googlebit.com/source/usr.bin/procstat/procstat_threads.c?v=8-CURRE
NT |
| 329 */ |
| 330 static PyObject* |
| 331 get_process_threads(PyObject* self, PyObject* args) |
| 332 { |
| 333 long pid; |
| 334 int mib[4]; |
| 335 struct kinfo_proc *kip; |
| 336 struct kinfo_proc *kipp; |
| 337 int error; |
| 338 unsigned int i; |
| 339 size_t size; |
| 340 PyObject* retList = PyList_New(0); |
| 341 PyObject* pyTuple = NULL; |
324 | 342 |
325 // convert a timeval struct to a double | 343 if (! PyArg_ParseTuple(args, "l", &pid)) { |
326 #define TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) | 344 return NULL; |
| 345 } |
| 346 |
| 347 /* |
| 348 * We need to re-query for thread information, so don't use *kipp. |
| 349 */ |
| 350 mib[0] = CTL_KERN; |
| 351 mib[1] = KERN_PROC; |
| 352 mib[2] = KERN_PROC_PID | KERN_PROC_INC_THREAD; |
| 353 mib[3] = pid; |
| 354 |
| 355 size = 0; |
| 356 error = sysctl(mib, 4, NULL, &size, NULL, 0); |
| 357 if (error == -1) { |
| 358 PyErr_SetFromErrno(PyExc_OSError); |
| 359 return NULL; |
| 360 » } |
| 361 if (size == 0) { |
| 362 return NoSuchProcess(); |
| 363 } |
| 364 |
| 365 kip = malloc(size); |
| 366 if (kip == NULL) { |
| 367 PyErr_SetFromErrno(PyExc_OSError); |
| 368 return NULL; |
| 369 } |
| 370 |
| 371 error = sysctl(mib, 4, kip, &size, NULL, 0); |
| 372 if (error == -1) { |
| 373 PyErr_SetFromErrno(PyExc_OSError); |
| 374 return NULL; |
| 375 } |
| 376 if (size == 0) { |
| 377 return NoSuchProcess(); |
| 378 } |
| 379 |
| 380 for (i = 0; i < size / sizeof(*kipp); i++) { |
| 381 kipp = &kip[i]; |
| 382 pyTuple = Py_BuildValue("Idd", kipp->ki_tid, |
| 383 TV2DOUBLE(kipp->ki_rusage.ru_utime), |
| 384 TV2DOUBLE(kipp->ki_rusage.ru_stime) |
| 385 ); |
| 386 PyList_Append(retList, pyTuple); |
| 387 Py_XDECREF(pyTuple); |
| 388 } |
| 389 free(kip); |
| 390 return retList; |
| 391 } |
327 | 392 |
328 | 393 |
329 /* | 394 /* |
330 * Return a Python tuple (user_time, kernel_time) | 395 * Return a Python tuple (user_time, kernel_time) |
331 */ | 396 */ |
332 static PyObject* | 397 static PyObject* |
333 get_cpu_times(PyObject* self, PyObject* args) | 398 get_cpu_times(PyObject* self, PyObject* args) |
334 { | 399 { |
335 long pid; | 400 long pid; |
336 double user_t, sys_t; | 401 double user_t, sys_t; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
384 return NULL; | 449 return NULL; |
385 } | 450 } |
386 if (get_kinfo_proc(pid, &kp) == -1) { | 451 if (get_kinfo_proc(pid, &kp) == -1) { |
387 return NULL; | 452 return NULL; |
388 } | 453 } |
389 return Py_BuildValue("d", TV2DOUBLE(kp.ki_start)); | 454 return Py_BuildValue("d", TV2DOUBLE(kp.ki_start)); |
390 } | 455 } |
391 | 456 |
392 | 457 |
393 /* | 458 /* |
| 459 * Return a Python float indicating the process create time expressed in |
| 460 * seconds since the epoch. |
| 461 */ |
| 462 static PyObject* |
| 463 get_process_io_counters(PyObject* self, PyObject* args) |
| 464 { |
| 465 long pid; |
| 466 struct kinfo_proc kp; |
| 467 if (! PyArg_ParseTuple(args, "l", &pid)) { |
| 468 return NULL; |
| 469 } |
| 470 if (get_kinfo_proc(pid, &kp) == -1) { |
| 471 return NULL; |
| 472 } |
| 473 // there's apparently no way to determine bytes count, hence return -1. |
| 474 return Py_BuildValue("(llll)", kp.ki_rusage.ru_inblock, |
| 475 kp.ki_rusage.ru_oublock, |
| 476 -1, -1); |
| 477 } |
| 478 |
| 479 |
| 480 |
| 481 /* |
394 * Return the RSS and VMS as a Python tuple. | 482 * Return the RSS and VMS as a Python tuple. |
395 */ | 483 */ |
396 static PyObject* | 484 static PyObject* |
397 get_memory_info(PyObject* self, PyObject* args) | 485 get_memory_info(PyObject* self, PyObject* args) |
398 { | 486 { |
399 long pid; | 487 long pid; |
400 struct kinfo_proc kp; | 488 struct kinfo_proc kp; |
401 if (! PyArg_ParseTuple(args, "l", &pid)) { | 489 if (! PyArg_ParseTuple(args, "l", &pid)) { |
402 return NULL; | 490 return NULL; |
403 } | 491 } |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
539 long cpu_time[CPUSTATES]; | 627 long cpu_time[CPUSTATES]; |
540 size_t size; | 628 size_t size; |
541 | 629 |
542 size = sizeof(cpu_time); | 630 size = sizeof(cpu_time); |
543 | 631 |
544 if (sysctlbyname("kern.cp_time", &cpu_time, &size, NULL, 0) == -1) { | 632 if (sysctlbyname("kern.cp_time", &cpu_time, &size, NULL, 0) == -1) { |
545 PyErr_SetFromErrno(0); | 633 PyErr_SetFromErrno(0); |
546 return NULL; | 634 return NULL; |
547 } | 635 } |
548 | 636 |
549 /* | |
550 #define CP_USER 0 | |
551 #define CP_NICE 1 | |
552 #define CP_SYS 2 | |
553 #define CP_INTR 3 | |
554 #define CP_IDLE 4 | |
555 #define CPUSTATES 5 | |
556 */ | |
557 //user, nice, system, idle, iowait, irqm, softirq | |
558 return Py_BuildValue("(ddddd)", | 637 return Py_BuildValue("(ddddd)", |
559 (double)cpu_time[CP_USER] / CLOCKS_PER_SEC, | 638 (double)cpu_time[CP_USER] / CLOCKS_PER_SEC, |
560 (double)cpu_time[CP_NICE] / CLOCKS_PER_SEC, | 639 (double)cpu_time[CP_NICE] / CLOCKS_PER_SEC, |
561 (double)cpu_time[CP_SYS] / CLOCKS_PER_SEC, | 640 (double)cpu_time[CP_SYS] / CLOCKS_PER_SEC, |
562 (double)cpu_time[CP_IDLE] / CLOCKS_PER_SEC, | 641 (double)cpu_time[CP_IDLE] / CLOCKS_PER_SEC, |
563 (double)cpu_time[CP_INTR] / CLOCKS_PER_SEC | 642 (double)cpu_time[CP_INTR] / CLOCKS_PER_SEC |
564 ); | 643 ); |
565 } | 644 } |
566 | 645 |
| 646 |
| 647 /* |
| 648 * Return a Python list of tuple representing per-cpu times |
| 649 */ |
| 650 static PyObject* |
| 651 get_system_per_cpu_times(PyObject* self, PyObject* args) |
| 652 { |
| 653 static int maxcpus; |
| 654 int mib[2]; |
| 655 int ncpu; |
| 656 size_t len; |
| 657 size_t size; |
| 658 int i; |
| 659 PyObject* py_retlist = PyList_New(0); |
| 660 PyObject* py_cputime; |
| 661 |
| 662 // retrieve maxcpus value |
| 663 size = sizeof(maxcpus); |
| 664 if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) { |
| 665 PyErr_SetFromErrno(0); |
| 666 return NULL; |
| 667 } |
| 668 long cpu_time[maxcpus][CPUSTATES]; |
| 669 |
| 670 // retrieve the number of cpus |
| 671 mib[0] = CTL_HW; |
| 672 mib[1] = HW_NCPU; |
| 673 len = sizeof(ncpu); |
| 674 if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) { |
| 675 PyErr_SetFromErrno(0); |
| 676 return NULL; |
| 677 } |
| 678 |
| 679 // per-cpu info |
| 680 size = sizeof(cpu_time); |
| 681 if (sysctlbyname("kern.cp_times", &cpu_time, &size, NULL, 0) == -1) { |
| 682 PyErr_SetFromErrno(0); |
| 683 return NULL; |
| 684 } |
| 685 |
| 686 for (i = 0; i < ncpu; i++) { |
| 687 py_cputime = Py_BuildValue("(ddddd)", |
| 688 (double)cpu_time[i][CP_USER] / CLOCKS_PER_SEC, |
| 689 (double)cpu_time[i][CP_NICE] / CLOCKS_PER_SEC, |
| 690 (double)cpu_time[i][CP_SYS] / CLOCKS_PER_SEC, |
| 691 (double)cpu_time[i][CP_IDLE] / CLOCKS_PER_SEC, |
| 692 (double)cpu_time[i][CP_INTR] / CLOCKS_PER_SEC |
| 693 ); |
| 694 PyList_Append(py_retlist, py_cputime); |
| 695 Py_XDECREF(py_cputime); |
| 696 } |
| 697 |
| 698 return py_retlist; |
| 699 } |
| 700 |
| 701 |
| 702 /* |
| 703 * Return a list of tuples including device, mount point and fs type |
| 704 * for all partitions mounted on the system. |
| 705 */ |
| 706 static PyObject* |
| 707 get_disk_partitions(PyObject* self, PyObject* args) |
| 708 { |
| 709 int num; |
| 710 int i; |
| 711 long len; |
| 712 struct statfs *fs; |
| 713 PyObject* py_retlist = PyList_New(0); |
| 714 PyObject* py_tuple; |
| 715 |
| 716 // get the number of mount points |
| 717 Py_BEGIN_ALLOW_THREADS |
| 718 num = getfsstat(NULL, 0, MNT_NOWAIT); |
| 719 Py_END_ALLOW_THREADS |
| 720 if (num == -1) { |
| 721 PyErr_SetFromErrno(0); |
| 722 return NULL; |
| 723 } |
| 724 |
| 725 len = sizeof(*fs) * num; |
| 726 fs = malloc(len); |
| 727 |
| 728 Py_BEGIN_ALLOW_THREADS |
| 729 num = getfsstat(fs, len, MNT_NOWAIT); |
| 730 Py_END_ALLOW_THREADS |
| 731 if (num == -1) { |
| 732 free(fs); |
| 733 PyErr_SetFromErrno(0); |
| 734 return NULL; |
| 735 } |
| 736 |
| 737 for (i = 0; i < num; i++) { |
| 738 py_tuple = Py_BuildValue("(sss)", fs[i].f_mntfromname, // device |
| 739 fs[i].f_mntonname, // mount point |
| 740 fs[i].f_fstypename); // fs type |
| 741 PyList_Append(py_retlist, py_tuple); |
| 742 Py_XDECREF(py_tuple); |
| 743 } |
| 744 |
| 745 free(fs); |
| 746 return py_retlist; |
| 747 } |
| 748 |
| 749 |
| 750 /* |
| 751 * Return a Python list of named tuples with overall network I/O information |
| 752 */ |
| 753 static PyObject* |
| 754 get_network_io_counters(PyObject* self, PyObject* args) |
| 755 { |
| 756 PyObject* py_retdict = PyDict_New(); |
| 757 PyObject* py_ifc_info; |
| 758 |
| 759 char *buf = NULL, *lim, *next; |
| 760 struct if_msghdr *ifm; |
| 761 int mib[6]; |
| 762 size_t len; |
| 763 |
| 764 mib[0] = CTL_NET; // networking subsystem |
| 765 mib[1] = PF_ROUTE; // type of information |
| 766 mib[2] = 0; // protocol (IPPROTO_xxx) |
| 767 mib[3] = 0; // address family |
| 768 mib[4] = NET_RT_IFLIST; // operation |
| 769 mib[5] = 0; |
| 770 |
| 771 if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { |
| 772 Py_DECREF(py_retdict); |
| 773 PyErr_SetFromErrno(0); |
| 774 return NULL; |
| 775 } |
| 776 |
| 777 |
| 778 buf = malloc(len); |
| 779 |
| 780 if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { |
| 781 if (buf) { |
| 782 free(buf); |
| 783 } |
| 784 Py_DECREF(py_retdict); |
| 785 PyErr_SetFromErrno(0); |
| 786 return NULL; |
| 787 } |
| 788 |
| 789 lim = buf + len; |
| 790 |
| 791 for (next = buf; next < lim; ) { |
| 792 ifm = (struct if_msghdr *)next; |
| 793 next += ifm->ifm_msglen; |
| 794 |
| 795 if (ifm->ifm_type == RTM_IFINFO) { |
| 796 struct if_msghdr *if2m = (struct if_msghdr *)ifm; |
| 797 struct sockaddr_dl *sdl = (struct sockaddr_dl *)(if2m + 1); |
| 798 char ifc_name[32]; |
| 799 |
| 800 strncpy(ifc_name, sdl->sdl_data, sdl->sdl_nlen); |
| 801 ifc_name[sdl->sdl_nlen] = 0; |
| 802 |
| 803 py_ifc_info = Py_BuildValue("(KKKK)", |
| 804 if2m->ifm_data.ifi_obytes, |
| 805 if2m->ifm_data.ifi_ibytes, |
| 806 if2m->ifm_data.ifi_opackets, |
| 807 if2m->ifm_data.ifi_ipackets); |
| 808 PyDict_SetItemString(py_retdict, ifc_name, py_ifc_info); |
| 809 Py_XDECREF(py_ifc_info); |
| 810 } |
| 811 else { |
| 812 continue; |
| 813 } |
| 814 } |
| 815 |
| 816 return py_retdict; |
| 817 } |
| 818 |
| 819 |
| 820 |
| 821 |
| 822 /* |
| 823 * define the psutil C module methods and initialize the module. |
| 824 */ |
| 825 static PyMethodDef |
| 826 PsutilMethods[] = |
| 827 { |
| 828 // --- per-process functions |
| 829 |
| 830 {"get_process_name", get_process_name, METH_VARARGS, |
| 831 "Return process name"}, |
| 832 {"get_process_exe", get_process_exe, METH_VARARGS, |
| 833 "Return process pathname executable"}, |
| 834 {"get_process_cmdline", get_process_cmdline, METH_VARARGS, |
| 835 "Return process cmdline as a list of cmdline arguments"}, |
| 836 {"get_process_ppid", get_process_ppid, METH_VARARGS, |
| 837 "Return process ppid as an integer"}, |
| 838 {"get_process_uids", get_process_uids, METH_VARARGS, |
| 839 "Return process real effective and saved user ids as a Python tuple"}, |
| 840 {"get_process_gids", get_process_gids, METH_VARARGS, |
| 841 "Return process real effective and saved group ids as a Python tuple"}, |
| 842 {"get_cpu_times", get_cpu_times, METH_VARARGS, |
| 843 "Return tuple of user/kern time for the given PID"}, |
| 844 {"get_process_create_time", get_process_create_time, METH_VARARGS, |
| 845 "Return a float indicating the process create time expressed in " |
| 846 "seconds since the epoch"}, |
| 847 {"get_memory_info", get_memory_info, METH_VARARGS, |
| 848 "Return a tuple of RSS/VMS memory information"}, |
| 849 {"get_process_num_threads", get_process_num_threads, METH_VARARGS, |
| 850 "Return number of threads used by process"}, |
| 851 {"get_process_threads", get_process_threads, METH_VARARGS, |
| 852 "Return process threads"}, |
| 853 {"get_process_status", get_process_status, METH_VARARGS, |
| 854 "Return process status as an integer"}, |
| 855 {"get_process_io_counters", get_process_io_counters, METH_VARARGS, |
| 856 "Return process IO counters"}, |
| 857 {"get_process_tty_nr", get_process_tty_nr, METH_VARARGS, |
| 858 "Return process tty (terminal) number"}, |
| 859 |
| 860 |
| 861 // --- system-related functions |
| 862 |
| 863 {"get_pid_list", get_pid_list, METH_VARARGS, |
| 864 "Returns a list of PIDs currently running on the system"}, |
| 865 {"get_num_cpus", get_num_cpus, METH_VARARGS, |
| 866 "Return number of CPUs on the system"}, |
| 867 {"get_total_phymem", get_total_phymem, METH_VARARGS, |
| 868 "Return the total amount of physical memory, in bytes"}, |
| 869 {"get_avail_phymem", get_avail_phymem, METH_VARARGS, |
| 870 "Return the amount of available physical memory, in bytes"}, |
| 871 {"get_total_virtmem", get_total_virtmem, METH_VARARGS, |
| 872 "Return the total amount of virtual memory, in bytes"}, |
| 873 {"get_avail_virtmem", get_avail_virtmem, METH_VARARGS, |
| 874 "Return the amount of available virtual memory, in bytes"}, |
| 875 {"get_system_cpu_times", get_system_cpu_times, METH_VARARGS, |
| 876 "Return system cpu times as a tuple (user, system, nice, idle, irc)"}, |
| 877 {"get_system_per_cpu_times", get_system_per_cpu_times, METH_VARARGS, |
| 878 "Return system per-cpu times as a list of tuples"}, |
| 879 {"get_system_boot_time", get_system_boot_time, METH_VARARGS, |
| 880 "Return a float indicating the system boot time expressed in " |
| 881 "seconds since the epoch"}, |
| 882 {"get_disk_partitions", get_disk_partitions, METH_VARARGS, |
| 883 "Return a list of tuples including device, mount point and " |
| 884 "fs type for all partitions mounted on the system."}, |
| 885 {"get_network_io_counters", get_network_io_counters, METH_VARARGS, |
| 886 "Return dict of tuples of networks I/O information."}, |
| 887 |
| 888 {NULL, NULL, 0, NULL} |
| 889 }; |
| 890 |
| 891 struct module_state { |
| 892 PyObject *error; |
| 893 }; |
| 894 |
| 895 #if PY_MAJOR_VERSION >= 3 |
| 896 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) |
| 897 #else |
| 898 #define GETSTATE(m) (&_state) |
| 899 #endif |
| 900 |
| 901 #if PY_MAJOR_VERSION >= 3 |
| 902 |
| 903 static int |
| 904 psutil_bsd_traverse(PyObject *m, visitproc visit, void *arg) { |
| 905 Py_VISIT(GETSTATE(m)->error); |
| 906 return 0; |
| 907 } |
| 908 |
| 909 static int |
| 910 psutil_bsd_clear(PyObject *m) { |
| 911 Py_CLEAR(GETSTATE(m)->error); |
| 912 return 0; |
| 913 } |
| 914 |
| 915 static struct PyModuleDef |
| 916 moduledef = { |
| 917 PyModuleDef_HEAD_INIT, |
| 918 "psutil_bsd", |
| 919 NULL, |
| 920 sizeof(struct module_state), |
| 921 PsutilMethods, |
| 922 NULL, |
| 923 psutil_bsd_traverse, |
| 924 psutil_bsd_clear, |
| 925 NULL |
| 926 }; |
| 927 |
| 928 #define INITERROR return NULL |
| 929 |
| 930 PyObject * |
| 931 PyInit__psutil_bsd(void) |
| 932 |
| 933 #else |
| 934 #define INITERROR return |
| 935 |
| 936 void init_psutil_bsd(void) |
| 937 #endif |
| 938 { |
| 939 #if PY_MAJOR_VERSION >= 3 |
| 940 PyObject *module = PyModule_Create(&moduledef); |
| 941 #else |
| 942 PyObject *module = Py_InitModule("_psutil_bsd", PsutilMethods); |
| 943 #endif |
| 944 PyModule_AddIntConstant(module, "SSTOP", SSTOP); |
| 945 PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); |
| 946 PyModule_AddIntConstant(module, "SRUN", SRUN); |
| 947 PyModule_AddIntConstant(module, "SIDL", SIDL); |
| 948 PyModule_AddIntConstant(module, "SWAIT", SWAIT); |
| 949 PyModule_AddIntConstant(module, "SLOCK", SLOCK); |
| 950 PyModule_AddIntConstant(module, "SZOMB", SZOMB); |
| 951 |
| 952 if (module == NULL) { |
| 953 INITERROR; |
| 954 } |
| 955 #if PY_MAJOR_VERSION >= 3 |
| 956 return module; |
| 957 #endif |
| 958 } |
| 959 |
OLD | NEW |