summaryrefslogtreecommitdiff
path: root/psutil/_psutil_osx.c
diff options
context:
space:
mode:
Diffstat (limited to 'psutil/_psutil_osx.c')
-rw-r--r--psutil/_psutil_osx.c144
1 files changed, 128 insertions, 16 deletions
diff --git a/psutil/_psutil_osx.c b/psutil/_psutil_osx.c
index 6e37bca5..f43bb010 100644
--- a/psutil/_psutil_osx.c
+++ b/psutil/_psutil_osx.c
@@ -38,6 +38,8 @@
#include <IOKit/storage/IOBlockStorageDriver.h>
#include <IOKit/storage/IOMedia.h>
#include <IOKit/IOBSD.h>
+#include <IOKit/ps/IOPowerSources.h>
+#include <IOKit/ps/IOPSKeys.h>
#include "_psutil_common.h"
#include "_psutil_posix.h"
@@ -273,9 +275,9 @@ psutil_proc_exe(PyObject *self, PyObject *args) {
ret = proc_pidpath((pid_t)pid, &buf, sizeof(buf));
if (ret == 0) {
if (pid == 0)
- AccessDenied();
+ AccessDenied("");
else
- psutil_raise_for_pid(pid, "proc_pidpath() syscall failed");
+ psutil_raise_for_pid(pid, "proc_pidpath()");
return NULL;
}
return PyUnicode_DecodeFSDefault(buf);
@@ -345,7 +347,16 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) {
err = task_for_pid(mach_task_self(), (pid_t)pid, &task);
if (err != KERN_SUCCESS) {
- psutil_raise_for_pid(pid, "task_for_pid() failed");
+ if ((err == 5) && (errno == ENOENT)) {
+ // See: https://github.com/giampaolo/psutil/issues/1181
+ psutil_debug("task_for_pid(MACH_PORT_NULL) failed; err=%i, "
+ "errno=%i, msg='%s'\n", err, errno,
+ mach_error_string(err));
+ AccessDenied("");
+ }
+ else {
+ psutil_raise_for_pid(pid, "task_for_pid(MACH_PORT_NULL)");
+ }
goto error;
}
@@ -356,8 +367,15 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) {
err = vm_region_recurse_64(task, &address, &size, &depth,
(vm_region_info_64_t)&info, &count);
- if (err == KERN_INVALID_ADDRESS)
+ if (err == KERN_INVALID_ADDRESS) {
+ // TODO temporary
+ psutil_debug("vm_region_recurse_64 returned KERN_INVALID_ADDRESS");
break;
+ }
+ if (err != KERN_SUCCESS) {
+ psutil_debug("vm_region_recurse_64 returned != KERN_SUCCESS");
+ }
+
if (info.is_submap) {
depth++;
}
@@ -385,8 +403,9 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) {
errno = 0;
proc_regionfilename((pid_t)pid, address, buf, sizeof(buf));
if ((errno != 0) || ((sizeof(buf)) <= 0)) {
- psutil_raise_for_pid(
- pid, "proc_regionfilename() syscall failed");
+ // TODO temporary
+ psutil_debug("proc_regionfilename() failed");
+ psutil_raise_for_pid(pid, "proc_regionfilename()");
goto error;
}
@@ -569,9 +588,9 @@ psutil_proc_memory_uss(PyObject *self, PyObject *args) {
err = task_for_pid(mach_task_self(), (pid_t)pid, &task);
if (err != KERN_SUCCESS) {
if (psutil_pid_exists(pid) == 0)
- NoSuchProcess();
+ NoSuchProcess("");
else
- AccessDenied();
+ AccessDenied("");
return NULL;
}
@@ -1016,9 +1035,9 @@ psutil_proc_threads(PyObject *self, PyObject *args) {
err = task_for_pid(mach_task_self(), (pid_t)pid, &task);
if (err != KERN_SUCCESS) {
if (psutil_pid_exists(pid) == 0)
- NoSuchProcess();
+ NoSuchProcess("");
else
- AccessDenied();
+ AccessDenied("");
goto error;
}
@@ -1028,7 +1047,7 @@ psutil_proc_threads(PyObject *self, PyObject *args) {
if (err != KERN_SUCCESS) {
// errcode 4 is "invalid argument" (access denied)
if (err == 4) {
- AccessDenied();
+ AccessDenied("");
}
else {
// otherwise throw a runtime error with appropriate error code
@@ -1138,7 +1157,6 @@ psutil_proc_open_files(PyObject *self, PyObject *args) {
iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE);
for (i = 0; i < iterations; i++) {
- py_tuple = NULL;
fdp_pointer = &fds_pointer[i];
if (fdp_pointer->proc_fdtype == PROX_FDTYPE_VNODE) {
@@ -1157,7 +1175,8 @@ psutil_proc_open_files(PyObject *self, PyObject *args) {
continue;
}
else {
- psutil_raise_for_pid(pid, "proc_pidinfo() syscall failed");
+ psutil_raise_for_pid(
+ pid, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO)");
goto error;
}
}
@@ -1176,7 +1195,9 @@ psutil_proc_open_files(PyObject *self, PyObject *args) {
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
+ py_tuple = NULL;
Py_DECREF(py_path);
+ py_path = NULL;
// --- /construct python list
}
}
@@ -1267,7 +1288,8 @@ psutil_proc_connections(PyObject *self, PyObject *args) {
continue;
}
else {
- psutil_raise_for_pid(pid, "proc_pidinfo() syscall failed");
+ psutil_raise_for_pid(
+ pid, "proc_pidinfo(PROC_PIDFDSOCKETINFO)");
goto error;
}
}
@@ -1785,6 +1807,92 @@ psutil_cpu_stats(PyObject *self, PyObject *args) {
}
+/*
+ * Return battery information.
+ */
+static PyObject *
+psutil_sensors_battery(PyObject *self, PyObject *args) {
+ PyObject *py_tuple = NULL;
+ CFTypeRef power_info = NULL;
+ CFArrayRef power_sources_list = NULL;
+ CFDictionaryRef power_sources_information = NULL;
+ CFNumberRef capacity_ref = NULL;
+ CFNumberRef time_to_empty_ref = NULL;
+ CFStringRef ps_state_ref = NULL;
+ uint32_t capacity; /* units are percent */
+ int time_to_empty; /* units are minutes */
+ int is_power_plugged;
+
+ power_info = IOPSCopyPowerSourcesInfo();
+
+ if (!power_info) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "IOPSCopyPowerSourcesInfo() syscall failed");
+ goto error;
+ }
+
+ power_sources_list = IOPSCopyPowerSourcesList(power_info);
+ if (!power_sources_list) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "IOPSCopyPowerSourcesList() syscall failed");
+ goto error;
+ }
+
+ /* Should only get one source. But in practice, check for > 0 sources */
+ if (!CFArrayGetCount(power_sources_list)) {
+ PyErr_SetString(PyExc_NotImplementedError, "no battery");
+ goto error;
+ }
+
+ power_sources_information = IOPSGetPowerSourceDescription(
+ power_info, CFArrayGetValueAtIndex(power_sources_list, 0));
+
+ capacity_ref = (CFNumberRef) CFDictionaryGetValue(
+ power_sources_information, CFSTR(kIOPSCurrentCapacityKey));
+ if (!CFNumberGetValue(capacity_ref, kCFNumberSInt32Type, &capacity)) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "No battery capacity infomration in power sources info");
+ goto error;
+ }
+
+ ps_state_ref = (CFStringRef) CFDictionaryGetValue(
+ power_sources_information, CFSTR(kIOPSPowerSourceStateKey));
+ is_power_plugged = CFStringCompare(
+ ps_state_ref, CFSTR(kIOPSACPowerValue), 0)
+ == kCFCompareEqualTo;
+
+ time_to_empty_ref = (CFNumberRef) CFDictionaryGetValue(
+ power_sources_information, CFSTR(kIOPSTimeToEmptyKey));
+ if (!CFNumberGetValue(time_to_empty_ref,
+ kCFNumberIntType, &time_to_empty)) {
+ /* This value is recommended for non-Apple power sources, so it's not
+ * an error if it doesn't exist. We'll return -1 for "unknown" */
+ /* A value of -1 indicates "Still Calculating the Time" also for
+ * apple power source */
+ time_to_empty = -1;
+ }
+
+ py_tuple = Py_BuildValue("Iii",
+ capacity, time_to_empty, is_power_plugged);
+ if (!py_tuple) {
+ goto error;
+ }
+
+ CFRelease(power_info);
+ CFRelease(power_sources_list);
+ /* Caller should NOT release power_sources_information */
+
+ return py_tuple;
+
+error:
+ if (power_info)
+ CFRelease(power_info);
+ if (power_sources_list)
+ CFRelease(power_sources_list);
+ Py_XDECREF(py_tuple);
+ return NULL;
+}
+
/*
* define the psutil C module methods and initialize the module.
@@ -1851,10 +1959,12 @@ PsutilMethods[] = {
"Return currently connected users as a list of tuples"},
{"cpu_stats", psutil_cpu_stats, METH_VARARGS,
"Return CPU statistics"},
+ {"sensors_battery", psutil_sensors_battery, METH_VARARGS,
+ "Return battery information."},
// --- others
- {"py_psutil_testing", py_psutil_testing, METH_VARARGS,
- "Return True if PSUTIL_TESTING env var is set"},
+ {"set_testing", psutil_set_testing, METH_NOARGS,
+ "Set psutil in testing mode"},
{NULL, NULL, 0, NULL}
};
@@ -1935,6 +2045,8 @@ init_psutil_osx(void)
PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT);
PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE);
+ psutil_setup();
+
if (module == NULL)
INITERROR;
#if PY_MAJOR_VERSION >= 3