summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/index.rst16
-rw-r--r--psutil/__init__.py8
-rw-r--r--psutil/_psbsd.py10
-rw-r--r--psutil/_pslinux.py14
-rw-r--r--psutil/_psosx.py5
-rw-r--r--psutil/_psutil_bsd.c2
-rw-r--r--psutil/_psutil_osx.c13
-rw-r--r--psutil/_psutil_windows.c35
-rw-r--r--psutil/_pswindows.py4
-rw-r--r--psutil/arch/freebsd/specific.c35
-rw-r--r--psutil/arch/freebsd/specific.h3
-rw-r--r--psutil/tests/__init__.py5
-rwxr-xr-xpsutil/tests/test_contracts.py3
-rwxr-xr-xpsutil/tests/test_memory_leaks.py6
-rwxr-xr-xpsutil/tests/test_process.py6
15 files changed, 156 insertions, 9 deletions
diff --git a/docs/index.rst b/docs/index.rst
index d58e1c19..b35c89bf 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1876,11 +1876,21 @@ Process class
(OpenBSD) "laddr" and "raddr" fields for UNIX sockets are always set to
"". This is a limitation of the OS.
+ .. note::
+ (AIX) :class:`psutil.AccessDenied` is always raised unless running
+ as root (lsof does the same).
+
.. versionchanged:: 5.3.0 : "laddr" and "raddr" are named tuples.
- .. note::
- (AIX) :class:`psutil.AccessDenied` is always raised unless running
- as root (lsof does the same).
+ .. method:: is64bit()
+
+ Return ``True`` if this is a 64-bit process, ``False`` if not, ``None`` if
+ undetermined. It can be assumed that ``False`` means 32-bit unless you have
+ a very old or exotic hardware.
+
+ Availability: Linux, Windows, OSX, FreeBSD
+
+ .. versionadded:: 5.4.0
.. method:: is_running()
diff --git a/psutil/__init__.py b/psutil/__init__.py
index 5e29a7fc..8f929846 100644
--- a/psutil/__init__.py
+++ b/psutil/__init__.py
@@ -844,6 +844,14 @@ class Process(object):
"""
return self._proc.num_handles()
+ if hasattr(_psplatform.Process, "is64bit"):
+
+ def is64bit(self):
+ """Return True if this is a 64 bit process, False if not,
+ None if it cannot be determined.
+ """
+ return self._proc.is64bit()
+
def num_ctx_switches(self):
"""Return the number of voluntary and involuntary context
switches performed by this process.
diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py
index 0553401a..c2c926e2 100644
--- a/psutil/_psbsd.py
+++ b/psutil/_psbsd.py
@@ -871,3 +871,13 @@ class Process(object):
@wrap_exceptions
def memory_maps(self):
return cext.proc_memory_maps(self.pid)
+
+ @wrap_exceptions
+ def is64bit(self):
+ name = cext.proc_abi_vector(self.pid)
+ if name in ("FreeBSD ELF64", "Linux ELF64"):
+ return True
+ elif name in ("FreeBSD ELF32", "Linux ELF32"):
+ return False
+ else:
+ return None
diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py
index b57adb34..06f1aa6b 100644
--- a/psutil/_pslinux.py
+++ b/psutil/_pslinux.py
@@ -1971,3 +1971,17 @@ class Process(object):
data = self._read_status_file()
real, effective, saved = _gids_re.findall(data)[0]
return _common.pgids(int(real), int(effective), int(saved))
+
+ @wrap_exceptions
+ def is64bit(self):
+ path = self.exe()
+ if not _common.path_exists_strict(path):
+ return None
+ with open_binary(path) as f:
+ header = f.read(5)
+ if header == b'\x7fELF\x02':
+ return True
+ elif header == b'\x7fELF\x01':
+ return False
+ else:
+ return None
diff --git a/psutil/_psosx.py b/psutil/_psosx.py
index 308756a8..f149980f 100644
--- a/psutil/_psosx.py
+++ b/psutil/_psosx.py
@@ -74,6 +74,7 @@ kinfo_proc_map = dict(
ctime=8,
status=9,
name=10,
+ is64bit=11,
)
pidtaskinfo_map = dict(
@@ -569,3 +570,7 @@ class Process(object):
def memory_maps(self):
with catch_zombie(self):
return cext.proc_memory_maps(self.pid)
+
+ @wrap_exceptions
+ def is64bit(self):
+ return self._get_kinfo_proc()[kinfo_proc_map['is64bit']]
diff --git a/psutil/_psutil_bsd.c b/psutil/_psutil_bsd.c
index 9a2ed04b..09ae0c30 100644
--- a/psutil/_psutil_bsd.c
+++ b/psutil/_psutil_bsd.c
@@ -945,6 +945,8 @@ PsutilMethods[] = {
"Set process CPU affinity."},
{"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS,
"Return an XML string to determine the number physical CPUs."},
+ {"proc_abi_vector", psutil_proc_abi_vector, METH_VARARGS,
+ "Return process ABI vector name (to check process bitness)"},
#endif
// --- system-related functions
diff --git a/psutil/_psutil_osx.c b/psutil/_psutil_osx.c
index 55dd64ca..f43bb010 100644
--- a/psutil/_psutil_osx.c
+++ b/psutil/_psutil_osx.c
@@ -136,6 +136,7 @@ psutil_proc_kinfo_oneshot(PyObject *self, PyObject *args) {
struct kinfo_proc kp;
PyObject *py_name;
PyObject *py_retlist;
+ PyObject *py_is64bit;
if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
@@ -150,8 +151,14 @@ psutil_proc_kinfo_oneshot(PyObject *self, PyObject *args) {
py_name = Py_None;
}
+ if (kp.kp_proc.p_flag & P_LP64)
+ py_is64bit = Py_True;
+ else
+ py_is64bit = Py_False;
+ Py_INCREF(py_is64bit);
+
py_retlist = Py_BuildValue(
- "lllllllidiO",
+ "lllllllidiOO",
(long)kp.kp_eproc.e_ppid, // (long) ppid
(long)kp.kp_eproc.e_pcred.p_ruid, // (long) real uid
(long)kp.kp_eproc.e_ucred.cr_uid, // (long) effective uid
@@ -162,12 +169,14 @@ psutil_proc_kinfo_oneshot(PyObject *self, PyObject *args) {
kp.kp_eproc.e_tdev, // (int) tty nr
PSUTIL_TV2DOUBLE(kp.kp_proc.p_starttime), // (double) create time
(int)kp.kp_proc.p_stat, // (int) status
- py_name // (pystr) name
+ py_name, // (str) name
+ py_is64bit // (bool) bitness
);
if (py_retlist != NULL) {
// XXX shall we decref() also in case of Py_BuildValue() error?
Py_DECREF(py_name);
+ Py_DECREF(py_is64bit);
}
return py_retlist;
}
diff --git a/psutil/_psutil_windows.c b/psutil/_psutil_windows.c
index 81d1b4a0..21738e8c 100644
--- a/psutil/_psutil_windows.c
+++ b/psutil/_psutil_windows.c
@@ -3572,6 +3572,39 @@ psutil_sensors_battery(PyObject *self, PyObject *args) {
}
+/*
+ * Return True if process is 64 bit else False.
+ */
+static PyObject *
+psutil_proc_is64bit(PyObject *self, PyObject *args) {
+ long pid;
+ SYSTEM_INFO sysinfo;
+ HANDLE hProcess;
+ BOOL isWow64;
+
+ GetNativeSystemInfo(&sysinfo);
+ if (sysinfo.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_AMD64)
+ return Py_False;
+
+ if (! PyArg_ParseTuple(args, "l", &pid))
+ return NULL;
+
+ hProcess = psutil_handle_from_pid(pid);
+ if (hProcess == NULL)
+ return NULL;
+
+ if (! IsWow64Process(hProcess, &isWow64)) {
+ CloseHandle(hProcess);
+ return PyErr_SetFromWindowsErr(0);
+ }
+ CloseHandle(hProcess);
+ if (isWow64)
+ return Py_False;
+ else
+ return Py_True;
+}
+
+
// ------------------------ Python init ---------------------------
static PyMethodDef
@@ -3633,6 +3666,8 @@ PsutilMethods[] = {
"Return the number of handles opened by process."},
{"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS,
"Return a list of process's memory mappings"},
+ {"proc_is64bit", psutil_proc_is64bit, METH_VARARGS,
+ "Return True if process is 64 bit else False."},
// --- alternative pinfo interface
{"proc_info", psutil_proc_info, METH_VARARGS,
diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py
index b6c58c93..505846e7 100644
--- a/psutil/_pswindows.py
+++ b/psutil/_pswindows.py
@@ -991,3 +991,7 @@ class Process(object):
ctx_switches = self.oneshot_info()[pinfo_map['ctx_switches']]
# only voluntary ctx switches are supported
return _common.pctxsw(ctx_switches, 0)
+
+ @wrap_exceptions
+ def is64bit(self):
+ return cext.proc_is64bit(self.pid)
diff --git a/psutil/arch/freebsd/specific.c b/psutil/arch/freebsd/specific.c
index 2c8944dd..52e2ae4a 100644
--- a/psutil/arch/freebsd/specific.c
+++ b/psutil/arch/freebsd/specific.c
@@ -1007,3 +1007,38 @@ error:
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
+
+
+/*
+ * Return process ABI vector name (to check process bitness).
+ */
+PyObject *
+psutil_proc_abi_vector(PyObject *self, PyObject *args) {
+ long pid;
+ size_t len;
+ int error;
+ int mib[4];
+ char progt[32];
+ size_t i;
+ len = sizeof(progt);
+
+ if (! PyArg_ParseTuple(args, "l", &pid))
+ return NULL;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_SV_NAME;
+ mib[3] = pid;
+ error = sysctl(mib, 4, progt, &len, NULL, 0);
+
+ if (error == -1) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+ }
+ if (len == 0) {
+ PyErr_SetString(PyExc_RuntimeError, "size mismatch");
+ return NULL;
+ }
+
+ return Py_BuildValue("s", progt);
+}
diff --git a/psutil/arch/freebsd/specific.h b/psutil/arch/freebsd/specific.h
index 0df66ecc..588abe8a 100644
--- a/psutil/arch/freebsd/specific.h
+++ b/psutil/arch/freebsd/specific.h
@@ -27,6 +27,5 @@ PyObject* psutil_proc_threads(PyObject* self, PyObject* args);
PyObject* psutil_swap_mem(PyObject* self, PyObject* args);
PyObject* psutil_virtual_mem(PyObject* self, PyObject* args);
PyObject* psutil_cpu_stats(PyObject* self, PyObject* args);
-#if defined(PSUTIL_FREEBSD)
PyObject* psutil_sensors_battery(PyObject* self, PyObject* args);
-#endif
+PyObject* psutil_proc_abi_vector(PyObject* self, PyObject* args);
diff --git a/psutil/tests/__init__.py b/psutil/tests/__init__.py
index 9e8d8596..0890b6f9 100644
--- a/psutil/tests/__init__.py
+++ b/psutil/tests/__init__.py
@@ -70,8 +70,8 @@ __all__ = [
'VERBOSITY',
"HAS_CPU_AFFINITY", "HAS_CPU_FREQ", "HAS_ENVIRON", "HAS_PROC_IO_COUNTERS",
"HAS_IONICE", "HAS_MEMORY_MAPS", "HAS_PROC_CPU_NUM", "HAS_RLIMIT",
- "HAS_SENSORS_BATTERY", "HAS_BATTERY", "HAS_SENSORS_FANS",
- "HAS_SENSORS_TEMPERATURES", "HAS_MEMORY_FULL_INFO",
+ "HAS_SENSORS_BATTERY", "HAS_BATTERY""HAS_SENSORS_FANS",
+ "HAS_SENSORS_TEMPERATURES", "HAS_MEMORY_FULL_INFO", "HAS_IS64BIT",
# subprocesses
'pyrun', 'reap_children', 'get_test_subprocess', 'create_zombie_proc',
'create_proc_children_pair',
@@ -154,6 +154,7 @@ HAS_CONNECTIONS_UNIX = POSIX and not SUNOS
HAS_ENVIRON = hasattr(psutil.Process, "environ")
HAS_PROC_IO_COUNTERS = hasattr(psutil.Process, "io_counters")
HAS_IONICE = hasattr(psutil.Process, "ionice")
+HAS_IS64BIT = hasattr(psutil.Process, "is64bit")
HAS_MEMORY_FULL_INFO = 'uss' in psutil.Process().memory_full_info()._fields
HAS_MEMORY_MAPS = hasattr(psutil.Process, "memory_maps")
HAS_PROC_CPU_NUM = hasattr(psutil.Process, "cpu_num")
diff --git a/psutil/tests/test_contracts.py b/psutil/tests/test_contracts.py
index 855b53bf..f9543e57 100755
--- a/psutil/tests/test_contracts.py
+++ b/psutil/tests/test_contracts.py
@@ -646,6 +646,9 @@ class TestFetchAllProcesses(unittest.TestCase):
self.assertIsInstance(k, str)
self.assertIsInstance(v, str)
+ def is64bit(self, ret, proc):
+ self.assertIn(ret, (True, False, None))
+
if __name__ == '__main__':
run_test_module_by_name(__file__)
diff --git a/psutil/tests/test_memory_leaks.py b/psutil/tests/test_memory_leaks.py
index 680fe780..bd23ff02 100755
--- a/psutil/tests/test_memory_leaks.py
+++ b/psutil/tests/test_memory_leaks.py
@@ -37,6 +37,7 @@ from psutil.tests import HAS_CPU_AFFINITY
from psutil.tests import HAS_CPU_FREQ
from psutil.tests import HAS_ENVIRON
from psutil.tests import HAS_IONICE
+from psutil.tests import HAS_IS64BIT
from psutil.tests import HAS_MEMORY_MAPS
from psutil.tests import HAS_PROC_CPU_NUM
from psutil.tests import HAS_PROC_IO_COUNTERS
@@ -383,6 +384,11 @@ class TestProcessObjectLeaks(TestMemLeak):
def test_proc_info(self):
self.execute(cext.proc_info, os.getpid())
+ @skip_if_linux()
+ @unittest.skipIf(not HAS_IS64BIT, "not supported")
+ def test_is64bit(self):
+ self.execute(self.proc.is64bit)
+
class TestTerminatedProcessLeaks(TestProcessObjectLeaks):
"""Repeat the tests above looking for leaks occurring when dealing
diff --git a/psutil/tests/test_process.py b/psutil/tests/test_process.py
index a629cae5..3b60d38a 100755
--- a/psutil/tests/test_process.py
+++ b/psutil/tests/test_process.py
@@ -13,6 +13,7 @@ import itertools
import os
import signal
import socket
+import struct
import subprocess
import sys
import tempfile
@@ -45,6 +46,7 @@ from psutil.tests import get_winver
from psutil.tests import HAS_CPU_AFFINITY
from psutil.tests import HAS_ENVIRON
from psutil.tests import HAS_IONICE
+from psutil.tests import HAS_IS64BIT
from psutil.tests import HAS_MEMORY_MAPS
from psutil.tests import HAS_PROC_CPU_NUM
from psutil.tests import HAS_PROC_IO_COUNTERS
@@ -677,6 +679,10 @@ class TestProcess(unittest.TestCase):
assert 0 <= ret <= 100, ret
assert 0 <= ret <= 100, ret
+ @unittest.skipIf(not HAS_IS64BIT, "not supported")
+ def test_is64bit(self):
+ self.assertEqual(psutil.Process().is64bit(), struct.calcsize("P") == 8)
+
def test_is_running(self):
sproc = get_test_subprocess()
p = psutil.Process(sproc.pid)