Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Side by Side Diff: third_party/psutil/psutil/_psutil_osx.c

Issue 8159001: Update third_party/psutil and fix the licence issue with it. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: remove the suppression and unnecessary files. Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/psutil/psutil/_psutil_osx.h ('k') | third_party/psutil/psutil/_psutil_posix.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * $Id: _psutil_osx.c 780 2010-11-10 18:42:47Z jloden $ 2 * $Id: _psutil_osx.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 * OS X platform-specific module methods for _psutil_osx 8 * OS X platform-specific module methods for _psutil_osx
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 <stdbool.h> 14 #include <stdbool.h>
11 #include <stdlib.h> 15 #include <stdlib.h>
12 #include <stdio.h> 16 #include <stdio.h>
13 #include <signal.h>
14 #include <sys/sysctl.h> 17 #include <sys/sysctl.h>
15 #include <sys/vmmeter.h> 18 #include <sys/vmmeter.h>
19 #include <libproc.h>
20 #include <sys/proc_info.h>
21 #include <netinet/tcp_fsm.h>
22 #include <arpa/inet.h>
23 #include <net/if_dl.h>
16 24
17 #include <mach/mach.h> 25 #include <mach/mach.h>
18 #include <mach/task.h> 26 #include <mach/task.h>
19 #include <mach/mach_init.h> 27 #include <mach/mach_init.h>
20 #include <mach/host_info.h> 28 #include <mach/host_info.h>
21 #include <mach/mach_host.h> 29 #include <mach/mach_host.h>
22 #include <mach/mach_traps.h> 30 #include <mach/mach_traps.h>
23 #include <mach/shared_memory_server.h> 31 #include <mach/shared_memory_server.h>
24 32
33 #include <CoreFoundation/CoreFoundation.h>
34 #include <IOKit/IOKitLib.h>
35 #include <IOKit/storage/IOBlockStorageDriver.h>
36 #include <IOKit/storage/IOMedia.h>
37 #include <IOKit/IOBSD.h>
38
25 #include "_psutil_osx.h" 39 #include "_psutil_osx.h"
40 #include "_psutil_common.h"
26 #include "arch/osx/process_info.h" 41 #include "arch/osx/process_info.h"
27 42
28 43
29 /* 44 /*
30 * define the psutil C module methods and initialize the module.
31 */
32 static PyMethodDef
33 PsutilMethods[] =
34 {
35 // --- per-process functions
36
37 {"get_process_name", get_process_name, METH_VARARGS,
38 "Return process name"},
39 {"get_process_cmdline", get_process_cmdline, METH_VARARGS,
40 "Return process cmdline as a list of cmdline arguments"},
41 {"get_process_ppid", get_process_ppid, METH_VARARGS,
42 "Return process ppid as an integer"},
43 {"get_process_uid", get_process_uid, METH_VARARGS,
44 "Return process real user id as an integer"},
45 {"get_process_gid", get_process_gid, METH_VARARGS,
46 "Return process real group id as an integer"},
47 {"get_cpu_times", get_cpu_times, METH_VARARGS,
48 "Return tuple of user/kern time for the given PID"},
49 {"get_process_create_time", get_process_create_time, METH_VARARGS,
50 "Return a float indicating the process create time expressed in "
51 "seconds since the epoch"},
52 {"get_memory_info", get_memory_info, METH_VARARGS,
53 "Return a tuple of RSS/VMS memory information"},
54 {"get_process_num_threads", get_process_num_threads, METH_VARARGS,
55 "Return number of threads used by process"},
56
57 // --- system-related functions
58
59 {"get_pid_list", get_pid_list, METH_VARARGS,
60 "Returns a list of PIDs currently running on the system"},
61 {"get_num_cpus", get_num_cpus, METH_VARARGS,
62 "Return number of CPUs on the system"},
63 {"get_total_phymem", get_total_phymem, METH_VARARGS,
64 "Return the total amount of physical memory, in bytes"},
65 {"get_avail_phymem", get_avail_phymem, METH_VARARGS,
66 "Return the amount of available physical memory, in bytes"},
67 {"get_total_virtmem", get_total_virtmem, METH_VARARGS,
68 "Return the total amount of virtual memory, in bytes"},
69 {"get_avail_virtmem", get_avail_virtmem, METH_VARARGS,
70 "Return the amount of available virtual memory, in bytes"},
71 {"get_system_cpu_times", get_system_cpu_times, METH_VARARGS,
72 "Return system cpu times as a tuple (user, system, nice, idle, irc)"},
73
74 {NULL, NULL, 0, NULL}
75 };
76
77
78 /*
79 * Raises an OSError(errno=ESRCH, strerror="No such process") exception
80 * in Python.
81 */
82 static PyObject*
83 NoSuchProcess(void) {
84 errno = ESRCH;
85 return PyErr_SetFromErrno(PyExc_OSError);
86 }
87
88 /*
89 * Raises an OSError(errno=EPERM, strerror="Operation not permitted") exception
90 * in Python.
91 */
92 static PyObject*
93 AccessDenied(void) {
94 errno = EPERM;
95 return PyErr_SetFromErrno(PyExc_OSError);
96 }
97
98 struct module_state {
99 PyObject *error;
100 };
101
102 #if PY_MAJOR_VERSION >= 3
103 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
104 #else
105 #define GETSTATE(m) (&_state)
106 static struct module_state _state;
107 #endif
108
109 #if PY_MAJOR_VERSION >= 3
110
111 static int
112 psutil_osx_traverse(PyObject *m, visitproc visit, void *arg) {
113 Py_VISIT(GETSTATE(m)->error);
114 return 0;
115 }
116
117 static int
118 psutil_osx_clear(PyObject *m) {
119 Py_CLEAR(GETSTATE(m)->error);
120 return 0;
121 }
122
123
124 static struct PyModuleDef
125 moduledef = {
126 PyModuleDef_HEAD_INIT,
127 "psutil_osx",
128 NULL,
129 sizeof(struct module_state),
130 PsutilMethods,
131 NULL,
132 psutil_osx_traverse,
133 psutil_osx_clear,
134 NULL
135 };
136
137 #define INITERROR return NULL
138
139 PyObject *
140 PyInit__psutil_osx(void)
141
142 #else
143 #define INITERROR return
144
145 void
146 init_psutil_osx(void)
147 #endif
148 {
149 #if PY_MAJOR_VERSION >= 3
150 PyObject *module = PyModule_Create(&moduledef);
151 #else
152 PyObject *module = Py_InitModule("_psutil_osx", PsutilMethods);
153 #endif
154 if (module == NULL) {
155 INITERROR;
156 }
157 struct module_state *st = GETSTATE(module);
158
159 st->error = PyErr_NewException("_psutil_osx.Error", NULL, NULL);
160 if (st->error == NULL) {
161 Py_DECREF(module);
162 INITERROR;
163 }
164 #if PY_MAJOR_VERSION >= 3
165 return module;
166 #endif
167 }
168
169
170 /*
171 * Return a Python list of all the PIDs running on the system. 45 * Return a Python list of all the PIDs running on the system.
172 */ 46 */
173 static PyObject* 47 static PyObject*
174 get_pid_list(PyObject* self, PyObject* args) 48 get_pid_list(PyObject* self, PyObject* args)
175 { 49 {
176 kinfo_proc *proclist = NULL; 50 kinfo_proc *proclist = NULL;
177 kinfo_proc *orig_address = NULL; 51 kinfo_proc *orig_address = NULL;
178 size_t num_processes; 52 size_t num_processes;
179 size_t idx; 53 size_t idx;
180 PyObject *pid; 54 PyObject *pid;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
227 { 101 {
228 long pid; 102 long pid;
229 PyObject* arglist = NULL; 103 PyObject* arglist = NULL;
230 104
231 if (! PyArg_ParseTuple(args, "l", &pid)) { 105 if (! PyArg_ParseTuple(args, "l", &pid)) {
232 return NULL; 106 return NULL;
233 } 107 }
234 108
235 // get the commandline, defined in arch/osx/process_info.c 109 // get the commandline, defined in arch/osx/process_info.c
236 arglist = get_arg_list(pid); 110 arglist = get_arg_list(pid);
237 111 return arglist;
238 // get_arg_list() returns NULL only if getcmdargs failed with ESRCH
239 // (no process with that PID)
240 if (NULL == arglist) {
241 return PyErr_SetFromErrno(PyExc_OSError);
242 }
243 return Py_BuildValue("N", arglist);
244 } 112 }
245 113
246 114
247 /* 115 /*
248 * Return process parent pid from kinfo_proc as a Python integer. 116 * Return process parent pid from kinfo_proc as a Python integer.
249 */ 117 */
250 static PyObject* 118 static PyObject*
251 get_process_ppid(PyObject* self, PyObject* args) 119 get_process_ppid(PyObject* self, PyObject* args)
252 { 120 {
253 long pid; 121 long pid;
254 struct kinfo_proc kp; 122 struct kinfo_proc kp;
255 if (! PyArg_ParseTuple(args, "l", &pid)) { 123 if (! PyArg_ParseTuple(args, "l", &pid)) {
256 return NULL; 124 return NULL;
257 } 125 }
258 if (get_kinfo_proc(pid, &kp) == -1) { 126 if (get_kinfo_proc(pid, &kp) == -1) {
259 return NULL; 127 return NULL;
260 } 128 }
261 return Py_BuildValue("l", (long)kp.kp_eproc.e_ppid); 129 return Py_BuildValue("l", (long)kp.kp_eproc.e_ppid);
262 } 130 }
263 131
264 132
265 /* 133 /*
266 * Return process real uid from kinfo_proc as a Python integer. 134 * Return process real uid from kinfo_proc as a Python integer.
267 */ 135 */
268 static PyObject* 136 static PyObject*
269 get_process_uid(PyObject* self, PyObject* args) 137 get_process_uids(PyObject* self, PyObject* args)
270 { 138 {
271 long pid; 139 long pid;
272 struct kinfo_proc kp; 140 struct kinfo_proc kp;
273 if (! PyArg_ParseTuple(args, "l", &pid)) { 141 if (! PyArg_ParseTuple(args, "l", &pid)) {
274 return NULL; 142 return NULL;
275 } 143 }
276 if (get_kinfo_proc(pid, &kp) == -1) { 144 if (get_kinfo_proc(pid, &kp) == -1) {
277 return NULL; 145 return NULL;
278 } 146 }
279 return Py_BuildValue("l", (long)kp.kp_eproc.e_pcred.p_ruid); 147 return Py_BuildValue("lll", (long)kp.kp_eproc.e_pcred.p_ruid,
148 (long)kp.kp_eproc.e_ucred.cr_uid,
149 (long)kp.kp_eproc.e_pcred.p_svuid);
280 } 150 }
281 151
282 152
283 /* 153 /*
284 * Return process real group id from ki_comm as a Python integer. 154 * Return process real group id from ki_comm as a Python integer.
285 */ 155 */
286 static PyObject* 156 static PyObject*
287 get_process_gid(PyObject* self, PyObject* args) 157 get_process_gids(PyObject* self, PyObject* args)
288 { 158 {
289 long pid; 159 long pid;
290 struct kinfo_proc kp; 160 struct kinfo_proc kp;
291 if (! PyArg_ParseTuple(args, "l", &pid)) { 161 if (! PyArg_ParseTuple(args, "l", &pid)) {
292 return NULL; 162 return NULL;
293 } 163 }
294 if (get_kinfo_proc(pid, &kp) == -1) { 164 if (get_kinfo_proc(pid, &kp) == -1) {
295 return NULL; 165 return NULL;
296 } 166 }
297 return Py_BuildValue("l", (long)kp.kp_eproc.e_pcred.p_rgid); 167 return Py_BuildValue("lll", (long)kp.kp_eproc.e_pcred.p_rgid,
168 (long)kp.kp_eproc.e_ucred.cr_groups[0],
169 (long)kp.kp_eproc.e_pcred.p_svgid);
298 } 170 }
299 171
300 172
301 /* 173 /*
302 * Return 1 if PID exists in the current process list, else 0. 174 * Return process controlling terminal number as an integer.
303 */ 175 */
304 static int 176 static PyObject*
305 pid_exists(long pid) { 177 get_process_tty_nr(PyObject* self, PyObject* args)
306 int kill_ret; 178 {
307 179 long pid;
308 // save some time if it's an invalid PID 180 struct kinfo_proc kp;
309 if (pid < 0) { 181 if (! PyArg_ParseTuple(args, "l", &pid)) {
310 return 0; 182 return NULL;
311 } 183 }
312 184 if (get_kinfo_proc(pid, &kp) == -1) {
313 // if kill returns success of permission denied we know it's a valid PID 185 return NULL;
314 kill_ret = kill(pid , 0);
315 if ( (0 == kill_ret) || (EPERM == errno) ) {
316 return 1;
317 } 186 }
318 187 return Py_BuildValue("i", kp.kp_eproc.e_tdev);
319 // otherwise return 0 for PID not found
320 return 0;
321 } 188 }
322 189
323 190
324 /* 191 /*
325 * Return a Python integer indicating the number of CPUs on the system. 192 * Return a Python integer indicating the number of CPUs on the system.
326 */ 193 */
327 static PyObject* 194 static PyObject*
328 get_num_cpus(PyObject* self, PyObject* args) 195 get_num_cpus(PyObject* self, PyObject* args)
329 { 196 {
330 197
(...skipping 18 matching lines...) Expand all
349 216
350 /* 217 /*
351 * Return a Python tuple (user_time, kernel_time) 218 * Return a Python tuple (user_time, kernel_time)
352 */ 219 */
353 static PyObject* 220 static PyObject*
354 get_cpu_times(PyObject* self, PyObject* args) 221 get_cpu_times(PyObject* self, PyObject* args)
355 { 222 {
356 long pid; 223 long pid;
357 int err; 224 int err;
358 unsigned int info_count = TASK_BASIC_INFO_COUNT; 225 unsigned int info_count = TASK_BASIC_INFO_COUNT;
359 task_port_t task;// = (task_port_t)NULL; 226 task_port_t task; // = (task_port_t)NULL;
360 time_value_t user_time, system_time; 227 time_value_t user_time, system_time;
361 struct task_basic_info tasks_info; 228 struct task_basic_info tasks_info;
362 struct task_thread_times_info task_times; 229 struct task_thread_times_info task_times;
363 230
364 // the argument passed should be a process id
365 if (! PyArg_ParseTuple(args, "l", &pid)) { 231 if (! PyArg_ParseTuple(args, "l", &pid)) {
366 return NULL; 232 return NULL;
367 } 233 }
368 234
369 /* task_for_pid() requires special privileges 235 /* task_for_pid() requires special privileges
370 * "This function can be called only if the process is owned by the 236 * "This function can be called only if the process is owned by the
371 * procmod group or if the caller is root." 237 * procmod group or if the caller is root."
372 * - http://developer.apple.com/documentation/MacOSX/Conceptual/universal_bi nary/universal_binary_tips/chapter_5_section_19.html 238 * - http://developer.apple.com/documentation/MacOSX/Conceptual/universal_bi nary/universal_binary_tips/chapter_5_section_19.html */
373 */
374 err = task_for_pid(mach_task_self(), pid, &task); 239 err = task_for_pid(mach_task_self(), pid, &task);
375 if ( err == KERN_SUCCESS) { 240 if ( err == KERN_SUCCESS) {
376 info_count = TASK_BASIC_INFO_COUNT; 241 info_count = TASK_BASIC_INFO_COUNT;
377 err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, &info_c ount); 242 err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, &info_c ount);
378 if (err != KERN_SUCCESS) { 243 if (err != KERN_SUCCESS) {
379 if (err == 4) { // errcode 4 is "invalid argument" (access denie d) 244 // errcode 4 is "invalid argument" (access denied)
245 if (err == 4) {
380 return AccessDenied(); 246 return AccessDenied();
381 } 247 }
382 248
383 //otherwise throw a runtime error with appropriate error code 249 // otherwise throw a runtime error with appropriate error code
384 return PyErr_Format(PyExc_RuntimeError, "task_info(TASK_BASIC_IN FO) failed for pid %lu - %s (%i)", 250 return PyErr_Format(PyExc_RuntimeError,
385 pid, mach_error_string(err), err); 251 "task_info(TASK_BASIC_INFO) failed");
386
387 } 252 }
388 253
389 info_count = TASK_THREAD_TIMES_INFO_COUNT; 254 info_count = TASK_THREAD_TIMES_INFO_COUNT;
390 err = task_info(task, TASK_THREAD_TIMES_INFO, (task_info_t)&task_times, &info_count); 255 err = task_info(task, TASK_THREAD_TIMES_INFO,
256 (task_info_t)&task_times, &info_count);
391 if (err != KERN_SUCCESS) { 257 if (err != KERN_SUCCESS) {
392 if (err == 4) { // errcode 4 is "invalid argument" (access denie d) 258 // errcode 4 is "invalid argument" (access denied)
259 if (err == 4) {
393 return AccessDenied(); 260 return AccessDenied();
394 } 261 }
395 262 return PyErr_Format(PyExc_RuntimeError,
396 return PyErr_Format(PyExc_RuntimeError, "task_info(TASK_THREAD_T IMES_INFO) failed for pid %lu - %s (%i)", 263 "task_info(TASK_BASIC_INFO) failed");
397 pid, mach_error_string(err), err);
398 } 264 }
399 } 265 }
400 266
401 else { // task_for_pid failed 267 else { // task_for_pid failed
402 if (! pid_exists(pid) ) { 268 if (! pid_exists(pid) ) {
403 return NoSuchProcess(); 269 return NoSuchProcess();
404 } 270 }
405
406 // pid exists, so return AccessDenied error since task_for_pid() failed 271 // pid exists, so return AccessDenied error since task_for_pid() failed
407 return AccessDenied(); 272 return AccessDenied();
408 } 273 }
409 274
410 float user_t = -1.0; 275 float user_t = -1.0;
411 float sys_t = -1.0; 276 float sys_t = -1.0;
412 user_time = tasks_info.user_time; 277 user_time = tasks_info.user_time;
413 system_time = tasks_info.system_time; 278 system_time = tasks_info.system_time;
414 279
415 time_value_add(&user_time, &task_times.user_time); 280 time_value_add(&user_time, &task_times.user_time);
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
457 mach_port_t object_name; 322 mach_port_t object_name;
458 323
459 // the argument passed should be a process id 324 // the argument passed should be a process id
460 if (! PyArg_ParseTuple(args, "l", &pid)) { 325 if (! PyArg_ParseTuple(args, "l", &pid)) {
461 return NULL; 326 return NULL;
462 } 327 }
463 328
464 /* task_for_pid() requires special privileges 329 /* task_for_pid() requires special privileges
465 * "This function can be called only if the process is owned by the 330 * "This function can be called only if the process is owned by the
466 * procmod group or if the caller is root." 331 * procmod group or if the caller is root."
467 * - http://developer.apple.com/documentation/MacOSX/Conceptual/universal_bi nary/universal_binary_tips/chapter_5_section_19.html 332 * - http://developer.apple.com/documentation/MacOSX/Conceptual/universal_bi nary/universal_binary_tips/chapter_5_section_19.html */
468 */
469 err = task_for_pid(mach_task_self(), pid, &task); 333 err = task_for_pid(mach_task_self(), pid, &task);
470 if ( err == KERN_SUCCESS) { 334 if ( err == KERN_SUCCESS) {
471 info_count = TASK_BASIC_INFO_COUNT; 335 info_count = TASK_BASIC_INFO_COUNT;
472 err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, &info_c ount); 336 err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, &info_c ount);
473 if (err != KERN_SUCCESS) { 337 if (err != KERN_SUCCESS) {
474 if (err == 4) { // errcode 4 is "invalid argument" (access denie d) 338 if (err == 4) {
339 // errcode 4 is "invalid argument" (access denied)
475 return AccessDenied(); 340 return AccessDenied();
476 } 341 }
477 342 // otherwise throw a runtime error with appropriate error code
478 //otherwise throw a runtime error with appropriate error code 343 return PyErr_Format(PyExc_RuntimeError,
479 return PyErr_Format(PyExc_RuntimeError, "task_info(TASK_BASIC_IN FO) failed for pid %lu - %s (%i)", 344 "task_info(TASK_BASIC_INFO) failed");
480 pid, mach_error_string(err), err);
481 } 345 }
482 346
483 /* Issue #73 http://code.google.com/p/psutil/issues/detail?id=73 347 /* Issue #73 http://code.google.com/p/psutil/issues/detail?id=73
484 * adjust the virtual memory size down to account for 348 * adjust the virtual memory size down to account for
485 * shared memory that task_info.virtual_size includes w/every process 349 * shared memory that task_info.virtual_size includes w/every process
486 */ 350 */
487 info_count = VM_REGION_BASIC_INFO_COUNT_64; 351 info_count = VM_REGION_BASIC_INFO_COUNT_64;
488 err = vm_region_64(task, &address, &size, VM_REGION_BASIC_INFO, 352 err = vm_region_64(task, &address, &size, VM_REGION_BASIC_INFO,
489 (vm_region_info_t)&b_info, &info_count, &object_name); 353 (vm_region_info_t)&b_info, &info_count, &object_name);
490 if (err == KERN_SUCCESS) { 354 if (err == KERN_SUCCESS) {
491 if (b_info.reserved && size == (SHARED_TEXT_REGION_SIZE) && 355 if (b_info.reserved && size == (SHARED_TEXT_REGION_SIZE) &&
492 tasks_info.virtual_size > (SHARED_TEXT_REGION_SIZE + SHARED_DATA _REGION_SIZE)) { 356 tasks_info.virtual_size > (SHARED_TEXT_REGION_SIZE + SHARED_DATA _REGION_SIZE))
493 tasks_info.virtual_size -= (SHARED_TEXT_REGION_SIZE + SHARED _DATA_REGION_SIZE); 357 {
358 tasks_info.virtual_size -= (SHARED_TEXT_REGION_SIZE + SHARED_DAT A_REGION_SIZE);
494 } 359 }
495 } 360 }
496 } 361 }
497 362
498 else { 363 else {
499 if (! pid_exists(pid) ) { 364 if (! pid_exists(pid) ) {
500 return NoSuchProcess(); 365 return NoSuchProcess();
501 } 366 }
502 367
503 // pid exists, so return AccessDenied error since task_for_pid() failed 368 // pid exists, so return AccessDenied error since task_for_pid() failed
504 return AccessDenied(); 369 return AccessDenied();
505 } 370 }
506 371
507 return Py_BuildValue("(ll)", tasks_info.resident_size, tasks_info.virtual_si ze); 372 return Py_BuildValue("(ll)", tasks_info.resident_size, tasks_info.virtual_si ze);
508 } 373 }
509 374
510 375
511 /* 376 /*
512 * Return number of threads used by process as a Python integer. 377 * Return number of threads used by process as a Python integer.
513 */ 378 */
514 static PyObject* 379 static PyObject*
515 get_process_num_threads(PyObject* self, PyObject* args) 380 get_process_num_threads(PyObject* self, PyObject* args)
516 { 381 {
517 long pid; 382 long pid;
518 int err; 383 int err, ret;
519 unsigned int info_count = TASK_BASIC_INFO_COUNT; 384 unsigned int info_count = TASK_BASIC_INFO_COUNT;
520 mach_port_t task; 385 mach_port_t task;
521 struct task_basic_info tasks_info; 386 struct task_basic_info tasks_info;
522 thread_act_port_array_t thread_list; 387 thread_act_port_array_t thread_list;
523 mach_msg_type_number_t thread_count; 388 mach_msg_type_number_t thread_count;
524 389
525 // the argument passed should be a process id 390 // the argument passed should be a process id
526 if (! PyArg_ParseTuple(args, "l", &pid)) { 391 if (! PyArg_ParseTuple(args, "l", &pid)) {
527 return NULL; 392 return NULL;
528 } 393 }
529 394
530 /* task_for_pid() requires special privileges 395 /* task_for_pid() requires special privileges
531 * "This function can be called only if the process is owned by the 396 * "This function can be called only if the process is owned by the
532 * procmod group or if the caller is root." 397 * procmod group or if the caller is root."
533 * - http://developer.apple.com/documentation/MacOSX/Conceptual/universal_bi nary/universal_binary_tips/chapter_5_section_19.html 398 * - http://developer.apple.com/documentation/MacOSX/Conceptual/universal_bi nary/universal_binary_tips/chapter_5_section_19.html
534 */ 399 */
535 err = task_for_pid(mach_task_self(), pid, &task); 400 err = task_for_pid(mach_task_self(), pid, &task);
536 if ( err == KERN_SUCCESS) { 401 if ( err == KERN_SUCCESS) {
537 info_count = TASK_BASIC_INFO_COUNT; 402 info_count = TASK_BASIC_INFO_COUNT;
538 err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, &info_c ount); 403 err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, &info_c ount);
539 if (err != KERN_SUCCESS) { 404 if (err != KERN_SUCCESS) {
540 if (err == 4) { // errcode 4 is "invalid argument" (access denie d) 405 // errcode 4 is "invalid argument" (access denied)
406 if (err == 4) {
541 return AccessDenied(); 407 return AccessDenied();
542 } 408 }
543 409
544 //otherwise throw a runtime error with appropriate error code 410 // otherwise throw a runtime error with appropriate error code
545 return PyErr_Format(PyExc_RuntimeError, "task_info(TASK_BASIC_IN FO) failed for pid %lu - %s (%i)", 411 return PyErr_Format(PyExc_RuntimeError,
546 pid, mach_error_string(err), err); 412 "task_info(TASK_BASIC_INFO) failed");
547 } 413 }
548
549 err = task_threads(task, &thread_list, &thread_count); 414 err = task_threads(task, &thread_list, &thread_count);
550 if (err == KERN_SUCCESS) { 415 if (err == KERN_SUCCESS) {
416 ret = vm_deallocate(task, (vm_address_t)thread_list,
417 thread_count * sizeof(int));
418 if (ret != KERN_SUCCESS) {
419 printf("vm_deallocate() failed\n");
420 }
551 return Py_BuildValue("l", (long)thread_count); 421 return Py_BuildValue("l", (long)thread_count);
552 } 422 }
423 else {
424 return PyErr_Format(PyExc_RuntimeError, "task_thread() failed");
425 }
553 } 426 }
554
555
556 else { 427 else {
557 if (! pid_exists(pid) ) { 428 if (! pid_exists(pid) ) {
558 return NoSuchProcess(); 429 return NoSuchProcess();
559 } 430 }
560 431
561 // pid exists, so return AccessDenied error since task_for_pid() failed 432 // pid exists, so return AccessDenied error since task_for_pid() failed
562 return AccessDenied(); 433 return AccessDenied();
563 } 434 }
564 return NULL; 435 return NULL;
565 } 436 }
(...skipping 11 matching lines...) Expand all
577 size_t len; 448 size_t len;
578 449
579 mib[0] = CTL_HW; 450 mib[0] = CTL_HW;
580 mib[1] = HW_MEMSIZE; 451 mib[1] = HW_MEMSIZE;
581 len = sizeof(total_phymem); 452 len = sizeof(total_phymem);
582 453
583 if (sysctl(mib, 2, &total_phymem, &len, NULL, 0) == -1) { 454 if (sysctl(mib, 2, &total_phymem, &len, NULL, 0) == -1) {
584 PyErr_SetFromErrno(0); 455 PyErr_SetFromErrno(0);
585 return NULL; 456 return NULL;
586 } 457 }
587
588 return Py_BuildValue("L", total_phymem); 458 return Py_BuildValue("L", total_phymem);
589 } 459 }
590 460
591 461
592 /* 462 /*
593 * Return a Python long indicating the amount of available physical memory in 463 * Return a Python long indicating the amount of available physical memory in
594 * bytes. 464 * bytes.
595 */ 465 */
596 static PyObject* 466 static PyObject*
597 get_avail_phymem(PyObject* self, PyObject* args) 467 get_avail_phymem(PyObject* self, PyObject* args)
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
671 mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT; 541 mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
672 kern_return_t error; 542 kern_return_t error;
673 host_cpu_load_info_data_t r_load; 543 host_cpu_load_info_data_t r_load;
674 544
675 error = host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)& r_load, &count); 545 error = host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)& r_load, &count);
676 if (error != KERN_SUCCESS) { 546 if (error != KERN_SUCCESS) {
677 return PyErr_Format(PyExc_RuntimeError, 547 return PyErr_Format(PyExc_RuntimeError,
678 "Error in host_statistics(): %s", mach_error_string(error)); 548 "Error in host_statistics(): %s", mach_error_string(error));
679 } 549 }
680 550
681 //user, nice, system, idle, iowait, irqm, softirq
682 return Py_BuildValue("(dddd)", 551 return Py_BuildValue("(dddd)",
683 (double)r_load.cpu_ticks[CPU_STATE_USER] / CLK_TCK, 552 (double)r_load.cpu_ticks[CPU_STATE_USER] / CLK_TCK,
684 (double)r_load.cpu_ticks[CPU_STATE_NICE] / CLK_TCK, 553 (double)r_load.cpu_ticks[CPU_STATE_NICE] / CLK_TCK,
685 (double)r_load.cpu_ticks[CPU_STATE_SYSTEM] / CLK_TCK, 554 (double)r_load.cpu_ticks[CPU_STATE_SYSTEM] / CLK_TCK,
686 (double)r_load.cpu_ticks[CPU_STATE_IDLE] / CLK_TCK 555 (double)r_load.cpu_ticks[CPU_STATE_IDLE] / CLK_TCK
687 ); 556 );
688 } 557 }
689 558
559
560 /*
561 * Return a Python list of tuple representing per-cpu times
562 */
563 static PyObject*
564 get_system_per_cpu_times(PyObject* self, PyObject* args)
565 {
566 natural_t cpu_count;
567 processor_info_array_t info_array;
568 mach_msg_type_number_t info_count;
569 kern_return_t error;
570 processor_cpu_load_info_data_t* cpu_load_info;
571 PyObject* py_retlist = PyList_New(0);
572 PyObject* py_cputime;
573 int i, ret;
574
575 error = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO,
576 &cpu_count, &info_array, &info_count);
577 if (error != KERN_SUCCESS) {
578 return PyErr_Format(PyExc_RuntimeError,
579 "Error in host_processor_info(): %s", mach_error_string(error));
580 }
581
582 cpu_load_info = (processor_cpu_load_info_data_t*) info_array;
583
584 for (i = 0; i < cpu_count; i++) {
585 py_cputime = Py_BuildValue("(dddd)",
586 (double)cpu_load_info[i].cpu_ticks[CPU_STATE_USER] / CLK_TCK,
587 (double)cpu_load_info[i].cpu_ticks[CPU_STATE_NICE] / CLK_TCK,
588 (double)cpu_load_info[i].cpu_ticks[CPU_STATE_SYSTEM] / CLK_TCK,
589 (double)cpu_load_info[i].cpu_ticks[CPU_STATE_IDLE] / CLK_TCK
590 );
591 PyList_Append(py_retlist, py_cputime);
592 Py_XDECREF(py_cputime);
593 }
594
595 ret = vm_deallocate(mach_task_self(), (vm_address_t)info_array,
596 info_count * sizeof(int));
597 if (ret != KERN_SUCCESS) {
598 printf("vm_deallocate() failed\n");
599 }
600 return py_retlist;
601 }
602
603
604 /*
605 * Return a Python float indicating the system boot time expressed in
606 * seconds since the epoch.
607 */
608 static PyObject*
609 get_system_boot_time(PyObject* self, PyObject* args)
610 {
611 /* fetch sysctl "kern.boottime" */
612 static int request[2] = { CTL_KERN, KERN_BOOTTIME };
613 struct timeval result;
614 size_t result_len = sizeof result;
615 time_t boot_time = 0;
616
617 if (sysctl(request, 2, &result, &result_len, NULL, 0) == -1) {
618 PyErr_SetFromErrno(0);
619 return NULL;
620 }
621 boot_time = result.tv_sec;
622 return Py_BuildValue("f", (float)boot_time);
623 }
624
625
626 /*
627 * Return a list of tuples including device, mount point and fs type
628 * for all partitions mounted on the system.
629 */
630 static PyObject*
631 get_disk_partitions(PyObject* self, PyObject* args)
632 {
633 int num;
634 int i;
635 long len;
636 struct statfs *fs;
637 PyObject* py_retlist = PyList_New(0);
638 PyObject* py_tuple;
639
640 // get the number of mount points
641 Py_BEGIN_ALLOW_THREADS
642 num = getfsstat(NULL, 0, MNT_NOWAIT);
643 Py_END_ALLOW_THREADS
644 if (num == -1) {
645 PyErr_SetFromErrno(0);
646 return NULL;
647 }
648
649 len = sizeof(*fs) * num;
650 fs = malloc(len);
651
652 Py_BEGIN_ALLOW_THREADS
653 num = getfsstat(fs, len, MNT_NOWAIT);
654 Py_END_ALLOW_THREADS
655 if (num == -1) {
656 free(fs);
657 PyErr_SetFromErrno(0);
658 return NULL;
659 }
660
661 for (i = 0; i < num; i++) {
662 py_tuple = Py_BuildValue("(sss)", fs[i].f_mntfromname, // device
663 fs[i].f_mntonname, // mount point
664 fs[i].f_fstypename); // fs type
665 PyList_Append(py_retlist, py_tuple);
666 Py_XDECREF(py_tuple);
667 }
668
669 free(fs);
670 return py_retlist;
671 }
672
673
674 /*
675 * Return process status as a Python integer.
676 */
677 static PyObject*
678 get_process_status(PyObject* self, PyObject* args)
679 {
680 long pid;
681 struct kinfo_proc kp;
682 if (! PyArg_ParseTuple(args, "l", &pid)) {
683 return NULL;
684 }
685 if (get_kinfo_proc(pid, &kp) == -1) {
686 return NULL;
687 }
688 return Py_BuildValue("i", (int)kp.kp_proc.p_stat);
689 }
690
691
692 /*
693 * Return process threads
694 */
695 static PyObject*
696 get_process_threads(PyObject* self, PyObject* args)
697 {
698 long pid;
699 int err, j, ret;
700 kern_return_t kr;
701 unsigned int info_count = TASK_BASIC_INFO_COUNT;
702 mach_port_t task;
703 struct task_basic_info tasks_info;
704 thread_act_port_array_t thread_list;
705 thread_info_data_t thinfo;
706 thread_basic_info_t basic_info_th;
707 mach_msg_type_number_t thread_count, thread_info_count;
708
709 PyObject* retList = PyList_New(0);
710 PyObject* pyTuple = NULL;
711
712 // the argument passed should be a process id
713 if (! PyArg_ParseTuple(args, "l", &pid)) {
714 return NULL;
715 }
716
717 // task_for_pid() requires special privileges
718 err = task_for_pid(mach_task_self(), pid, &task);
719 if (err != KERN_SUCCESS) {
720 if (! pid_exists(pid) ) {
721 return NoSuchProcess();
722 }
723 return AccessDenied();
724 }
725
726 info_count = TASK_BASIC_INFO_COUNT;
727 err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, &info_count );
728 if (err != KERN_SUCCESS) {
729 // errcode 4 is "invalid argument" (access denied)
730 if (err == 4) {
731 return AccessDenied();
732 }
733 // otherwise throw a runtime error with appropriate error code
734 return PyErr_Format(PyExc_RuntimeError,
735 "task_info(TASK_BASIC_INFO) failed");
736 }
737
738 err = task_threads(task, &thread_list, &thread_count);
739 if (err != KERN_SUCCESS) {
740 return PyErr_Format(PyExc_RuntimeError, "task_threads() failed");
741 }
742
743 for (j = 0; j < thread_count; j++) {
744 thread_info_count = THREAD_INFO_MAX;
745 kr = thread_info(thread_list[j], THREAD_BASIC_INFO,
746 (thread_info_t)thinfo, &thread_info_count);
747 if (kr != KERN_SUCCESS) {
748 return PyErr_Format(PyExc_RuntimeError, "thread_info() failed");
749 }
750 basic_info_th = (thread_basic_info_t)thinfo;
751 // XXX - thread_info structure does not provide any process id;
752 // the best we can do is assigning an incremental bogus value
753 pyTuple = Py_BuildValue("Iff", j + 1,
754 (float)basic_info_th->user_time.microseconds / 1000000.0,
755 (float)basic_info_th->system_time.microseconds / 1000000.0
756 );
757 PyList_Append(retList, pyTuple);
758 Py_XDECREF(pyTuple);
759 }
760
761 ret = vm_deallocate(task, (vm_address_t)thread_list,
762 thread_count * sizeof(int));
763 if (ret != KERN_SUCCESS) {
764 printf("vm_deallocate() failed\n");
765 }
766
767 return retList;
768 }
769
770
771 /*
772 * Return process open files as a Python tuple.
773 * References:
774 * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/m78fd
775 * - /usr/include/sys/proc_info.h
776 */
777 static PyObject*
778 get_process_open_files(PyObject* self, PyObject* args)
779 {
780 long pid;
781 int pidinfo_result;
782 int iterations;
783 int i;
784 int nb;
785
786 struct proc_fdinfo *fds_pointer;
787 struct proc_fdinfo *fdp_pointer;
788 struct vnode_fdinfowithpath vi;
789
790 PyObject *retList = PyList_New(0);
791 PyObject *tuple = NULL;
792
793 if (! PyArg_ParseTuple(args, "l", &pid)) {
794 return NULL;
795 }
796
797 pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
798 if (pidinfo_result <= 0) {
799 goto error;
800 }
801
802 fds_pointer = malloc(pidinfo_result);
803 pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer,
804 pidinfo_result);
805 free(fds_pointer);
806
807 if (pidinfo_result <= 0) {
808 goto error;
809 }
810
811 iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE);
812
813 for (i = 0; i < iterations; i++) {
814 fdp_pointer = &fds_pointer[i];
815
816 //
817 if (fdp_pointer->proc_fdtype == PROX_FDTYPE_VNODE)
818 {
819 nb = proc_pidfdinfo(pid,
820 fdp_pointer->proc_fd,
821 PROC_PIDFDVNODEPATHINFO,
822 &vi,
823 sizeof(vi));
824
825 // --- errors checking
826 if (nb <= 0) {
827 if ((errno == ENOENT) || (errno == EBADF)) {
828 // no such file or directory or bad file descriptor;
829 // let's assume the file has been closed or removed
830 continue;
831 }
832 if (errno != 0) {
833 return PyErr_SetFromErrno(PyExc_OSError);
834 }
835 else
836 return PyErr_Format(PyExc_RuntimeError,
837 "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed");
838 }
839 if (nb < sizeof(vi)) {
840 return PyErr_Format(PyExc_RuntimeError,
841 "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed (buffer mismatch) ");
842 }
843 // --- /errors checking
844
845 // --- construct python list
846 tuple = Py_BuildValue("(si)", vi.pvip.vip_path,
847 (int)fdp_pointer->proc_fd);
848 PyList_Append(retList, tuple);
849 Py_DECREF(tuple);
850 // --- /construct python list
851 }
852 }
853
854 return retList;
855
856 error:
857 if (errno != 0)
858 return PyErr_SetFromErrno(PyExc_OSError);
859 else if (! pid_exists(pid) )
860 return NoSuchProcess();
861 else
862 return PyErr_Format(PyExc_RuntimeError,
863 "proc_pidinfo(PROC_PIDLISTFDS) failed");
864 }
865
866
867 /*
868 * mathes Linux net/tcp_states.h:
869 * http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
870 */
871 static char *
872 get_connection_status(int st) {
873 switch (st) {
874 case TCPS_CLOSED:
875 return "CLOSE";
876 case TCPS_CLOSING:
877 return "CLOSING";
878 case TCPS_CLOSE_WAIT:
879 return "CLOSE_WAIT";
880 case TCPS_LISTEN:
881 return "LISTEN";
882 case TCPS_ESTABLISHED:
883 return "ESTABLISHED";
884 case TCPS_SYN_SENT:
885 return "SYN_SENT";
886 case TCPS_SYN_RECEIVED:
887 return "SYN_RECV";
888 case TCPS_FIN_WAIT_1:
889 return "FIN_WAIT_1";
890 case TCPS_FIN_WAIT_2:
891 return "FIN_WAIT_2";
892 case TCPS_LAST_ACK:
893 return "LAST_ACK";
894 case TCPS_TIME_WAIT:
895 return "TIME_WAIT";
896 default:
897 return "";
898 }
899 }
900
901
902 /*
903 * Return process TCP and UDP connections as a list of tuples.
904 * References:
905 * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/wNrC0
906 * - /usr/include/sys/proc_info.h
907 */
908 static PyObject*
909 get_process_connections(PyObject* self, PyObject* args)
910 {
911 long pid;
912 int pidinfo_result;
913 int iterations;
914 int i;
915 int nb;
916
917 struct proc_fdinfo *fds_pointer;
918 struct proc_fdinfo *fdp_pointer;
919 struct socket_fdinfo si;
920
921
922 PyObject *retList = PyList_New(0);
923 PyObject *tuple = NULL;
924 PyObject *laddr = NULL;
925 PyObject *raddr = NULL;
926
927 if (! PyArg_ParseTuple(args, "l", &pid)) {
928 return NULL;
929 }
930
931 if (pid == 0) {
932 return retList;
933 }
934
935 pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
936 if (pidinfo_result <= 0) {
937 goto error;
938 }
939
940 fds_pointer = malloc(pidinfo_result);
941 pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer,
942 pidinfo_result);
943 free(fds_pointer);
944
945 if (pidinfo_result <= 0) {
946 goto error;
947 }
948
949 iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE);
950
951 for (i = 0; i < iterations; i++) {
952 errno = 0;
953 fdp_pointer = &fds_pointer[i];
954
955 //
956 if (fdp_pointer->proc_fdtype == PROX_FDTYPE_SOCKET)
957 {
958 nb = proc_pidfdinfo(pid, fdp_pointer->proc_fd, PROC_PIDFDSOCKETINFO,
959 &si, sizeof(si));
960
961 // --- errors checking
962 if (nb <= 0) {
963 if (errno == EBADF) {
964 // let's assume socket has been closed
965 continue;
966 }
967 if (errno != 0) {
968 return PyErr_SetFromErrno(PyExc_OSError);
969 }
970 else {
971 return PyErr_Format(PyExc_RuntimeError,
972 "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed");
973 }
974 }
975 if (nb < sizeof(si)) {
976 return PyErr_Format(PyExc_RuntimeError,
977 "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed (buffer mismatch) ");
978 }
979 // --- /errors checking
980
981 //
982 int fd, family, type, lport, rport;
983 char lip[200], rip[200];
984 char *state;
985
986 fd = (int)fdp_pointer->proc_fd;
987 family = si.psi.soi_family;
988 type = si.psi.soi_kind;
989
990 if ((family != AF_INET) && (family != AF_INET6)) {
991 continue;
992 }
993
994 if (type == 2)
995 type = SOCK_STREAM;
996 else if (type == 1)
997 type = SOCK_DGRAM;
998 else
999 continue;
1000
1001 if (errno != 0) {
1002 printf("errno 1 = %i\n", errno);
1003 return PyErr_SetFromErrno(PyExc_OSError);
1004 }
1005
1006
1007 if (family == AF_INET) {
1008 inet_ntop(AF_INET,
1009 &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_46. i46a_addr4,
1010 lip,
1011 sizeof(lip));
1012 inet_ntop(AF_INET,
1013 &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_46. i46a_addr4,
1014 rip,
1015 sizeof(lip));
1016 }
1017 else {
1018 inet_ntop(AF_INET6,
1019 &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_6,
1020 lip, sizeof(lip));
1021 inet_ntop(AF_INET6,
1022 &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_6,
1023 lip, sizeof(rip));
1024 }
1025
1026 // check for inet_ntop failures
1027 if (errno != 0) {
1028 return PyErr_SetFromErrno(PyExc_OSError);
1029 }
1030
1031 lport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport);
1032 rport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_fport);
1033 if (type == SOCK_STREAM)
1034 state = get_connection_status((int)si.psi.soi_proto.pri_tcp.tcps i_state);
1035 else
1036 state = "";
1037
1038 laddr = Py_BuildValue("(si)", lip, lport);
1039 if (rport != 0)
1040 raddr = Py_BuildValue("(si)", rip, rport);
1041 else
1042 raddr = PyTuple_New(0);
1043
1044 // --- construct python list
1045 tuple = Py_BuildValue("(iiiNNs)", fd, family, type, laddr, raddr,
1046 state);
1047 PyList_Append(retList, tuple);
1048 Py_DECREF(tuple);
1049 // --- /construct python list
1050 }
1051 }
1052
1053 return retList;
1054
1055 error:
1056 if (errno != 0)
1057 return PyErr_SetFromErrno(PyExc_OSError);
1058 else if (! pid_exists(pid) )
1059 return NoSuchProcess();
1060 else
1061 return PyErr_Format(PyExc_RuntimeError,
1062 "proc_pidinfo(PROC_PIDLISTFDS) failed");
1063 }
1064
1065
1066 /*
1067 * Return a Python list of named tuples with overall network I/O information
1068 */
1069 static PyObject*
1070 get_network_io_counters(PyObject* self, PyObject* args)
1071 {
1072 PyObject* py_retdict = PyDict_New();
1073 PyObject* py_ifc_info;
1074
1075 char *buf = NULL, *lim, *next;
1076 struct if_msghdr *ifm;
1077 int mib[6];
1078 size_t len;
1079
1080 mib[0] = CTL_NET; // networking subsystem
1081 mib[1] = PF_ROUTE; // type of information
1082 mib[2] = 0; // protocol (IPPROTO_xxx)
1083 mib[3] = 0; // address family
1084 mib[4] = NET_RT_IFLIST2; // operation
1085 mib[5] = 0;
1086
1087 if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
1088 Py_DECREF(py_retdict);
1089 PyErr_SetFromErrno(0);
1090 return NULL;
1091 }
1092
1093 buf = malloc(len);
1094
1095 if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
1096 if (buf) {
1097 free(buf);
1098 }
1099 Py_DECREF(py_retdict);
1100 PyErr_SetFromErrno(0);
1101 return NULL;
1102 }
1103
1104 lim = buf + len;
1105
1106 for (next = buf; next < lim; ) {
1107 ifm = (struct if_msghdr *)next;
1108 next += ifm->ifm_msglen;
1109
1110 if (ifm->ifm_type == RTM_IFINFO2) {
1111 struct if_msghdr2 *if2m = (struct if_msghdr2 *)ifm;
1112 struct sockaddr_dl *sdl = (struct sockaddr_dl *)(if2m + 1);
1113 char ifc_name[32];
1114
1115 strncpy(ifc_name, sdl->sdl_data, sdl->sdl_nlen);
1116 ifc_name[sdl->sdl_nlen] = 0;
1117
1118 py_ifc_info = Py_BuildValue("(KKKK)",
1119 if2m->ifm_data.ifi_obytes,
1120 if2m->ifm_data.ifi_ibytes,
1121 if2m->ifm_data.ifi_opackets,
1122 if2m->ifm_data.ifi_ipackets);
1123 PyDict_SetItemString(py_retdict, ifc_name, py_ifc_info);
1124 Py_XDECREF(py_ifc_info);
1125 }
1126 else {
1127 continue;
1128 }
1129 }
1130
1131 free(buf);
1132
1133 return py_retdict;
1134 }
1135
1136
1137 /*
1138 * Return a Python dict of tuples for disk I/O information
1139 */
1140 static PyObject*
1141 get_disk_io_counters(PyObject* self, PyObject* args)
1142 {
1143 PyObject* py_retdict = PyDict_New();
1144 PyObject* py_disk_info;
1145
1146 CFDictionaryRef parent_dict;
1147 CFDictionaryRef props_dict;
1148 CFDictionaryRef stats_dict;
1149 io_registry_entry_t parent;
1150 io_registry_entry_t disk;
1151 io_iterator_t disk_list;
1152
1153 /* Get list of disks */
1154 if (IOServiceGetMatchingServices(kIOMasterPortDefault,
1155 IOServiceMatching(kIOMediaClass),
1156 &disk_list) != kIOReturnSuccess) {
1157 Py_DECREF(py_retdict);
1158 PyErr_SetString(PyExc_RuntimeError, "Unable to get the list of disks.");
1159 return NULL;
1160 }
1161
1162 /* Iterate over disks */
1163 while ((disk = IOIteratorNext(disk_list)) != 0) {
1164 parent_dict = NULL;
1165 props_dict = NULL;
1166 stats_dict = NULL;
1167
1168 if (IORegistryEntryGetParentEntry(disk, kIOServicePlane, &parent) != kIO ReturnSuccess) {
1169 PyErr_SetString(PyExc_RuntimeError, "Unable to get the disk's parent .");
1170 Py_DECREF(py_retdict);
1171 IOObjectRelease(disk);
1172 return NULL;
1173 }
1174
1175 if (IOObjectConformsTo(parent, "IOBlockStorageDriver")) {
1176 if(IORegistryEntryCreateCFProperties(
1177 disk,
1178 (CFMutableDictionaryRef *) &parent_dict,
1179 kCFAllocatorDefault,
1180 kNilOptions) != kIOReturnSuccess)
1181 {
1182 PyErr_SetString(PyExc_RuntimeError,
1183 "Unable to get the parent's properties.");
1184 Py_DECREF(py_retdict);
1185 IOObjectRelease(disk);
1186 IOObjectRelease(parent);
1187 return NULL;
1188 }
1189
1190 if (IORegistryEntryCreateCFProperties(parent,
1191 (CFMutableDictionaryRef *) &props_dict ,
1192 kCFAllocatorDefault,
1193 kNilOptions) != kIOReturnSuccess)
1194 {
1195 PyErr_SetString(PyExc_RuntimeError,
1196 "Unable to get the disk properties.");
1197 Py_DECREF(py_retdict);
1198 IOObjectRelease(disk);
1199 return NULL;
1200 }
1201
1202 const int kMaxDiskNameSize = 64;
1203 CFStringRef disk_name_ref = (CFStringRef)CFDictionaryGetValue(
1204 parent_dict,
1205 CFSTR(kIOBSDNameKey));
1206 char disk_name[kMaxDiskNameSize];
1207
1208 CFStringGetCString(disk_name_ref,
1209 disk_name,
1210 kMaxDiskNameSize,
1211 CFStringGetSystemEncoding());
1212
1213 stats_dict = (CFDictionaryRef)CFDictionaryGetValue(
1214 props_dict,
1215 CFSTR(kIOBlockStorageDriverStatisticsKey));
1216
1217 if (stats_dict == NULL) {
1218 PyErr_SetString(PyExc_RuntimeError, "Unable to get disk stats.") ;
1219 Py_DECREF(py_retdict);
1220 CFRelease(props_dict);
1221 IOObjectRelease(disk);
1222 IOObjectRelease(parent);
1223 return NULL;
1224 }
1225
1226 CFNumberRef number;
1227 int64_t reads, writes, read_bytes, write_bytes, read_time, write_tim e = 0;
1228
1229 /* Get disk reads/writes */
1230 if ((number = (CFNumberRef)CFDictionaryGetValue(
1231 stats_dict,
1232 CFSTR(kIOBlockStorageDriverStatisticsReadsKey))))
1233 {
1234 CFNumberGetValue(number, kCFNumberSInt64Type, &reads);
1235 }
1236 if ((number = (CFNumberRef)CFDictionaryGetValue(
1237 stats_dict,
1238 CFSTR(kIOBlockStorageDriverStatisticsWritesKey))))
1239 {
1240 CFNumberGetValue(number, kCFNumberSInt64Type, &writes);
1241 }
1242
1243 /* Get disk bytes read/written */
1244 if ((number = (CFNumberRef)CFDictionaryGetValue(
1245 stats_dict,
1246 CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey))))
1247 {
1248 CFNumberGetValue(number, kCFNumberSInt64Type, &read_bytes);
1249 }
1250 if ((number = (CFNumberRef)CFDictionaryGetValue(
1251 stats_dict,
1252 CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey))))
1253 {
1254 CFNumberGetValue(number, kCFNumberSInt64Type, &write_bytes);
1255 }
1256
1257 /* Get disk time spent reading/writing (nanoseconds) */
1258 if ((number = (CFNumberRef)CFDictionaryGetValue(
1259 stats_dict,
1260 CFSTR(kIOBlockStorageDriverStatisticsTotalReadTimeKey))))
1261 {
1262 CFNumberGetValue(number, kCFNumberSInt64Type, &read_time);
1263 }
1264 if ((number = (CFNumberRef)CFDictionaryGetValue(
1265 stats_dict,
1266 CFSTR(kIOBlockStorageDriverStatisticsTotalWriteTimeKey)))) {
1267 CFNumberGetValue(number, kCFNumberSInt64Type, &write_time);
1268 }
1269
1270 py_disk_info = Py_BuildValue("(KKKKKK)",
1271 reads, writes,
1272 read_bytes, write_bytes,
1273 read_time, write_time);
1274 PyDict_SetItemString(py_retdict, disk_name, py_disk_info);
1275 Py_XDECREF(py_disk_info);
1276
1277 CFRelease(parent_dict);
1278 IOObjectRelease(parent);
1279 CFRelease(props_dict);
1280 IOObjectRelease(disk);
1281 }
1282 }
1283
1284 IOObjectRelease (disk_list);
1285
1286 return py_retdict;
1287 }
1288
1289
1290 /*
1291 * define the psutil C module methods and initialize the module.
1292 */
1293 static PyMethodDef
1294 PsutilMethods[] =
1295 {
1296 // --- per-process functions
1297
1298 {"get_process_name", get_process_name, METH_VARARGS,
1299 "Return process name"},
1300 {"get_process_cmdline", get_process_cmdline, METH_VARARGS,
1301 "Return process cmdline as a list of cmdline arguments"},
1302 {"get_process_ppid", get_process_ppid, METH_VARARGS,
1303 "Return process ppid as an integer"},
1304 {"get_process_uids", get_process_uids, METH_VARARGS,
1305 "Return process real user id as an integer"},
1306 {"get_process_gids", get_process_gids, METH_VARARGS,
1307 "Return process real group id as an integer"},
1308 {"get_cpu_times", get_cpu_times, METH_VARARGS,
1309 "Return tuple of user/kern time for the given PID"},
1310 {"get_process_create_time", get_process_create_time, METH_VARARGS,
1311 "Return a float indicating the process create time expressed in "
1312 "seconds since the epoch"},
1313 {"get_memory_info", get_memory_info, METH_VARARGS,
1314 "Return a tuple of RSS/VMS memory information"},
1315 {"get_process_num_threads", get_process_num_threads, METH_VARARGS,
1316 "Return number of threads used by process"},
1317 {"get_process_status", get_process_status, METH_VARARGS,
1318 "Return process status as an integer"},
1319 {"get_process_threads", get_process_threads, METH_VARARGS,
1320 "Return process threads as a list of tuples"},
1321 {"get_process_open_files", get_process_open_files, METH_VARARGS,
1322 "Return files opened by process as a list of tuples"},
1323 {"get_process_connections", get_process_connections, METH_VARARGS,
1324 "Get process TCP and UDP connections as a list of tuples"},
1325 {"get_process_tty_nr", get_process_tty_nr, METH_VARARGS,
1326 "Return process tty number as an integer"},
1327
1328 // --- system-related functions
1329
1330 {"get_pid_list", get_pid_list, METH_VARARGS,
1331 "Returns a list of PIDs currently running on the system"},
1332 {"get_num_cpus", get_num_cpus, METH_VARARGS,
1333 "Return number of CPUs on the system"},
1334 {"get_total_phymem", get_total_phymem, METH_VARARGS,
1335 "Return the total amount of physical memory, in bytes"},
1336 {"get_avail_phymem", get_avail_phymem, METH_VARARGS,
1337 "Return the amount of available physical memory, in bytes"},
1338 {"get_total_virtmem", get_total_virtmem, METH_VARARGS,
1339 "Return the total amount of virtual memory, in bytes"},
1340 {"get_avail_virtmem", get_avail_virtmem, METH_VARARGS,
1341 "Return the amount of available virtual memory, in bytes"},
1342 {"get_system_cpu_times", get_system_cpu_times, METH_VARARGS,
1343 "Return system cpu times as a tuple (user, system, nice, idle, irc)"},
1344 {"get_system_per_cpu_times", get_system_per_cpu_times, METH_VARARGS,
1345 "Return system per-cpu times as a list of tuples"},
1346 {"get_system_boot_time", get_system_boot_time, METH_VARARGS,
1347 "Return a float indicating the system boot time expressed in "
1348 "seconds since the epoch"},
1349 {"get_disk_partitions", get_disk_partitions, METH_VARARGS,
1350 "Return a list of tuples including device, mount point and "
1351 "fs type for all partitions mounted on the system."},
1352 {"get_network_io_counters", get_network_io_counters, METH_VARARGS,
1353 "Return dict of tuples of networks I/O information."},
1354 {"get_disk_io_counters", get_disk_io_counters, METH_VARARGS,
1355 "Return dict of tuples of disks I/O information."},
1356
1357 {NULL, NULL, 0, NULL}
1358 };
1359
1360
1361 struct module_state {
1362 PyObject *error;
1363 };
1364
1365 #if PY_MAJOR_VERSION >= 3
1366 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
1367 #else
1368 #define GETSTATE(m) (&_state)
1369 #endif
1370
1371 #if PY_MAJOR_VERSION >= 3
1372
1373 static int
1374 psutil_osx_traverse(PyObject *m, visitproc visit, void *arg) {
1375 Py_VISIT(GETSTATE(m)->error);
1376 return 0;
1377 }
1378
1379 static int
1380 psutil_osx_clear(PyObject *m) {
1381 Py_CLEAR(GETSTATE(m)->error);
1382 return 0;
1383 }
1384
1385
1386 static struct PyModuleDef
1387 moduledef = {
1388 PyModuleDef_HEAD_INIT,
1389 "psutil_osx",
1390 NULL,
1391 sizeof(struct module_state),
1392 PsutilMethods,
1393 NULL,
1394 psutil_osx_traverse,
1395 psutil_osx_clear,
1396 NULL
1397 };
1398
1399 #define INITERROR return NULL
1400
1401 PyObject *
1402 PyInit__psutil_osx(void)
1403
1404 #else
1405 #define INITERROR return
1406
1407 void
1408 init_psutil_osx(void)
1409 #endif
1410 {
1411 #if PY_MAJOR_VERSION >= 3
1412 PyObject *module = PyModule_Create(&moduledef);
1413 #else
1414 PyObject *module = Py_InitModule("_psutil_osx", PsutilMethods);
1415 #endif
1416 // process status constants, defined in:
1417 // http://fxr.watson.org/fxr/source/bsd/sys/proc.h?v=xnu-792.6.70#L149
1418 PyModule_AddIntConstant(module, "SIDL", SIDL);
1419 PyModule_AddIntConstant(module, "SRUN", SRUN);
1420 PyModule_AddIntConstant(module, "SSLEEP", SSLEEP);
1421 PyModule_AddIntConstant(module, "SSTOP", SSTOP);
1422 PyModule_AddIntConstant(module, "SZOMB", SZOMB);
1423
1424 if (module == NULL) {
1425 INITERROR;
1426 }
1427 #if PY_MAJOR_VERSION >= 3
1428 return module;
1429 #endif
1430 }
OLDNEW
« no previous file with comments | « third_party/psutil/psutil/_psutil_osx.h ('k') | third_party/psutil/psutil/_psutil_posix.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698