diff --git a/dev-python/psutil/patches/psutil-5.6.7.patchset b/dev-python/psutil/patches/psutil-5.6.7.patchset new file mode 100644 index 000000000..a3aaf063f --- /dev/null +++ b/dev-python/psutil/patches/psutil-5.6.7.patchset @@ -0,0 +1,1410 @@ +From cad8406514db2b2241d0e522ede4d19267c8e441 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= +Date: Wed, 12 Feb 2020 04:16:40 +0100 +Subject: [PATCH] WIP: preliminary Haiku port + +--- + psutil/__init__.py | 5 + + psutil/_common.py | 5 +- + psutil/_pshaiku.py | 433 ++++++++++++++++++++ + psutil/_psutil_haiku.cpp | 841 +++++++++++++++++++++++++++++++++++++++ + psutil/_psutil_posix.c | 5 +- + setup.py | 11 + + 6 files changed, 1297 insertions(+), 3 deletions(-) + create mode 100644 psutil/_pshaiku.py + create mode 100644 psutil/_psutil_haiku.cpp + +diff --git a/psutil/__init__.py b/psutil/__init__.py +index b267239..0ba8fc7 100644 +--- a/psutil/__init__.py ++++ b/psutil/__init__.py +@@ -16,6 +16,7 @@ sensors) in Python. Supported platforms: + - NetBSD + - Sun Solaris + - AIX ++ - Haiku + + Works with Python versions from 2.6 to 3.4+. + """ +@@ -79,6 +80,7 @@ from ._common import NIC_DUPLEX_UNKNOWN + from ._common import AIX + from ._common import BSD + from ._common import FREEBSD # NOQA ++from ._common import HAIKU + from ._common import LINUX + from ._common import MACOS + from ._common import NETBSD # NOQA +@@ -174,6 +176,9 @@ elif AIX: + # via sys.modules. + PROCFS_PATH = "/proc" + ++elif HAIKU: ++ from . import _pshaiku as _psplatform ++ + else: # pragma: no cover + raise NotImplementedError('platform %s is not supported' % sys.platform) + +diff --git a/psutil/_common.py b/psutil/_common.py +index 126d9d6..88ac58f 100644 +--- a/psutil/_common.py ++++ b/psutil/_common.py +@@ -42,8 +42,8 @@ PY3 = sys.version_info[0] == 3 + + __all__ = [ + # constants +- 'FREEBSD', 'BSD', 'LINUX', 'NETBSD', 'OPENBSD', 'MACOS', 'OSX', 'POSIX', +- 'SUNOS', 'WINDOWS', ++ 'FREEBSD', 'BSD', 'HAIKU', 'LINUX', 'NETBSD', 'OPENBSD', 'MACOS', 'OSX', ++ 'POSIX', 'SUNOS', 'WINDOWS', + 'ENCODING', 'ENCODING_ERRS', 'AF_INET6', + # connection constants + 'CONN_CLOSE', 'CONN_CLOSE_WAIT', 'CONN_CLOSING', 'CONN_ESTABLISHED', +@@ -84,6 +84,7 @@ NETBSD = sys.platform.startswith("netbsd") + BSD = FREEBSD or OPENBSD or NETBSD + SUNOS = sys.platform.startswith(("sunos", "solaris")) + AIX = sys.platform.startswith("aix") ++HAIKU = sys.platform.startswith("haiku") + + + # =================================================================== +diff --git a/psutil/_pshaiku.py b/psutil/_pshaiku.py +new file mode 100644 +index 0000000..89115f7 +--- /dev/null ++++ b/psutil/_pshaiku.py +@@ -0,0 +1,433 @@ ++# Copyright (c) 2009, Giampaolo Rodola' ++# Copyright (c) 2017, Arnon Yaari ++# Copyright (c) 2020, François Revol ++# All rights reserved. ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++"""Haiku platform implementation.""" ++ ++import functools ++# import glob ++import os ++# import re ++# import subprocess ++# import sys ++from collections import namedtuple ++ ++from . import _common ++from . import _psposix ++from . import _psutil_haiku as cext ++from . import _psutil_posix as cext_posix ++from ._common import AccessDenied ++# from ._common import conn_to_ntuple ++from ._common import memoize_when_activated ++from ._common import NoSuchProcess ++from ._common import usage_percent ++from ._common import ZombieProcess ++from ._compat import FileNotFoundError ++from ._compat import PermissionError ++from ._compat import ProcessLookupError ++# from ._compat import PY3 ++ ++ ++__extra__all__ = [] ++ ++ ++# ===================================================================== ++# --- globals ++# ===================================================================== ++ ++ ++HAS_NET_IO_COUNTERS = hasattr(cext, "net_io_counters") ++HAS_PROC_IO_COUNTERS = hasattr(cext, "proc_io_counters") ++ ++PAGE_SIZE = os.sysconf('SC_PAGE_SIZE') ++AF_LINK = cext_posix.AF_LINK ++ ++PROC_STATUSES = { ++ cext.B_THREAD_RUNNING: _common.STATUS_RUNNING, ++ cext.B_THREAD_READY: _common.STATUS_IDLE, ++ cext.B_THREAD_RECEIVING: _common.STATUS_WAITING, ++ cext.B_THREAD_ASLEEP: _common.STATUS_SLEEPING, ++ cext.B_THREAD_SUSPENDED: _common.STATUS_STOPPED, ++ cext.B_THREAD_WAITING: _common.STATUS_WAITING, ++} ++ ++team_info_map = dict( ++ thread_count=0, ++ image_count=1, ++ area_count=2, ++ uid=3, ++ gid=4, ++ name=5) ++ ++team_usage_info_map = dict( ++ user_time=0, ++ kernel_time=1) ++ ++thread_info_map = dict( ++ id=0, ++ user_time=1, ++ kernel_time=2, ++ state=3) ++ ++ ++# ===================================================================== ++# --- named tuples ++# ===================================================================== ++ ++ ++# psutil.Process.memory_info() ++pmem = namedtuple('pmem', ['rss', 'vms']) ++# psutil.Process.memory_full_info() ++pfullmem = pmem ++# psutil.Process.cpu_times() ++scputimes = namedtuple('scputimes', ['user', 'system', 'idle', 'iowait']) ++# psutil.virtual_memory() ++svmem = namedtuple('svmem', ['total', 'used', 'percent', 'cached', 'buffers', ++ 'ignored', 'needed', 'available']) ++ ++ ++# ===================================================================== ++# --- memory ++# ===================================================================== ++ ++ ++def virtual_memory(): ++ total, inuse, cached, buffers, ignored, needed, avail = cext.virtual_mem() ++ percent = usage_percent((total - avail), total, round_=1) ++ return svmem(total, inuse, percent, cached, buffers, ignored, needed, ++ avail) ++ ++ ++def swap_memory(): ++ """Swap system memory as a (total, used, free, sin, sout) tuple.""" ++ total, free = cext.swap_mem() ++ sin = 0 ++ sout = 0 ++ used = total - free ++ percent = usage_percent(used, total, round_=1) ++ return _common.sswap(total, used, free, percent, sin, sout) ++ ++ ++# ===================================================================== ++# --- CPU ++# ===================================================================== ++ ++ ++def cpu_times(): ++ """Return system-wide CPU times as a named tuple""" ++ ret = cext.per_cpu_times() ++ return scputimes(*[sum(x) for x in zip(*ret)]) ++ ++ ++def per_cpu_times(): ++ """Return system per-CPU times as a list of named tuples""" ++ ret = cext.per_cpu_times() ++ return [scputimes(*x) for x in ret] ++ ++ ++def cpu_count_logical(): ++ """Return the number of logical CPUs in the system.""" ++ try: ++ return os.sysconf("SC_NPROCESSORS_ONLN") ++ except ValueError: ++ # mimic os.cpu_count() behavior ++ return None ++ ++ ++def cpu_count_physical(): ++ # TODO: ++ return None ++ ++ ++def cpu_stats(): ++ """Return various CPU stats as a named tuple.""" ++ ctx_switches, interrupts, soft_interrupts, syscalls = cext.cpu_stats() ++ return _common.scpustats( ++ ctx_switches, interrupts, soft_interrupts, syscalls) ++ ++ ++def cpu_freq(): ++ """Return CPU frequency. ++ """ ++ curr, min_, max_ = cext.cpu_freq() ++ return [_common.scpufreq(curr, min_, max_)] ++ ++ ++# ===================================================================== ++# --- disks ++# ===================================================================== ++ ++ ++disk_io_counters = cext.disk_io_counters ++disk_usage = _psposix.disk_usage ++ ++ ++def disk_partitions(all=False): ++ """Return system disk partitions.""" ++ # TODO - the filtering logic should be better checked so that ++ # it tries to reflect 'df' as much as possible ++ retlist = [] ++ partitions = cext.disk_partitions() ++ for partition in partitions: ++ device, mountpoint, fstype, opts = partition ++ if device == 'none': ++ device = '' ++ if not all: ++ # Differently from, say, Linux, we don't have a list of ++ # common fs types so the best we can do, AFAIK, is to ++ # filter by filesystem having a total size > 0. ++ if not disk_usage(mountpoint).total: ++ continue ++ ntuple = _common.sdiskpart(device, mountpoint, fstype, opts) ++ retlist.append(ntuple) ++ return retlist ++ ++ ++# ===================================================================== ++# --- network ++# ===================================================================== ++ ++ ++net_if_addrs = cext_posix.net_if_addrs ++ ++if HAS_NET_IO_COUNTERS: ++ net_io_counters = cext.net_io_counters ++ ++ ++def net_connections(kind, _pid=-1): ++ """Return socket connections. If pid == -1 return system-wide ++ connections (as opposed to connections opened by one process only). ++ """ ++ # TODO ++ return None ++ ++ ++def net_if_stats(): ++ """Get NIC stats (isup, duplex, speed, mtu).""" ++ # TODO ++ return None ++ ++ ++# ===================================================================== ++# --- other system functions ++# ===================================================================== ++ ++ ++def boot_time(): ++ """The system boot time expressed in seconds since the epoch.""" ++ return cext.boot_time() ++ ++ ++def users(): ++ """Return currently connected users as a list of namedtuples.""" ++ retlist = [] ++ rawlist = cext.users() ++ localhost = (':0.0', ':0') ++ for item in rawlist: ++ user, tty, hostname, tstamp, user_process, pid = item ++ # note: the underlying C function includes entries about ++ # system boot, run level and others. We might want ++ # to use them in the future. ++ if not user_process: ++ continue ++ if hostname in localhost: ++ hostname = 'localhost' ++ nt = _common.suser(user, tty, hostname, tstamp, pid) ++ retlist.append(nt) ++ return retlist ++ ++ ++# ===================================================================== ++# --- processes ++# ===================================================================== ++ ++ ++def pids(): ++ ls = cext.pids() ++ return ls ++ ++ ++pid_exists = _psposix.pid_exists ++ ++ ++def wrap_exceptions(fun): ++ """Call callable into a try/except clause and translate ENOENT, ++ EACCES and EPERM in NoSuchProcess or AccessDenied exceptions. ++ """ ++ @functools.wraps(fun) ++ def wrapper(self, *args, **kwargs): ++ try: ++ return fun(self, *args, **kwargs) ++ except (FileNotFoundError, ProcessLookupError): ++ # ENOENT (no such file or directory) gets raised on open(). ++ # ESRCH (no such process) can get raised on read() if ++ # process is gone in meantime. ++ if not pid_exists(self.pid): ++ raise NoSuchProcess(self.pid, self._name) ++ else: ++ raise ZombieProcess(self.pid, self._name, self._ppid) ++ except PermissionError: ++ raise AccessDenied(self.pid, self._name) ++ return wrapper ++ ++ ++class Process(object): ++ """Wrapper class around underlying C implementation.""" ++ ++ __slots__ = ["pid", "_name", "_ppid", "_cache"] ++ ++ def __init__(self, pid): ++ self.pid = pid ++ self._name = None ++ self._ppid = None ++ ++ def oneshot_enter(self): ++ self._proc_team_info.cache_activate(self) ++ self._proc_team_usage_info.cache_activate(self) ++ ++ def oneshot_exit(self): ++ self._proc_team_info.cache_deactivate(self) ++ self._proc_team_usage_info.cache_deactivate(self) ++ ++ @wrap_exceptions ++ @memoize_when_activated ++ def _proc_team_info(self): ++ ret = cext.proc_team_info_oneshot(self.pid) ++ print("%d %d\n" % (len(ret), len(team_info_map))) ++ assert len(ret) == len(team_info_map) ++ return ret ++ ++ @wrap_exceptions ++ @memoize_when_activated ++ def _proc_team_usage_info(self): ++ ret = cext.proc_team_usage_info_oneshot(self.pid) ++ print("%d %d\n" % (len(ret), len(team_usage_info_map))) ++ assert len(ret) == len(team_usage_info_map) ++ return ret ++ ++ @wrap_exceptions ++ def name(self): ++ return cext.proc_name(self.pid).rstrip("\x00") ++ ++ @wrap_exceptions ++ def exe(self): ++ return cext.proc_exe(self.pid) ++ ++ @wrap_exceptions ++ def cmdline(self): ++ return cext.proc_cmdline(self.pid) ++ ++ @wrap_exceptions ++ def environ(self): ++ return cext.proc_environ(self.pid) ++ ++ @wrap_exceptions ++ def create_time(self): ++ return None ++ ++ @wrap_exceptions ++ def num_threads(self): ++ return self._proc_team_info()[team_info_map['thread_count']] ++ ++ @wrap_exceptions ++ def threads(self): ++ rawlist = cext.proc_threads(self.pid) ++ retlist = [] ++ for thread_id, utime, stime, state in rawlist: ++ ntuple = _common.pthread(thread_id, utime, stime) ++ retlist.append(ntuple) ++ return retlist ++ ++ @wrap_exceptions ++ def connections(self, kind='inet'): ++ ret = net_connections(kind, _pid=self.pid) ++ # The underlying C implementation retrieves all OS connections ++ # and filters them by PID. At this point we can't tell whether ++ # an empty list means there were no connections for process or ++ # process is no longer active so we force NSP in case the PID ++ # is no longer there. ++ if not ret: ++ # will raise NSP if process is gone ++ os.stat('%s/%s' % (self._procfs_path, self.pid)) ++ return ret ++ ++ @wrap_exceptions ++ def nice_get(self): ++ return cext_posix.getpriority(self.pid) ++ ++ @wrap_exceptions ++ def nice_set(self, value): ++ return cext_posix.setpriority(self.pid, value) ++ ++ @wrap_exceptions ++ def ppid(self): ++ return None ++ ++ @wrap_exceptions ++ def uids(self): ++ uid = self._proc_team_info()[team_info_map['uid']] ++ return _common.puids(uid, uid, uid) ++ ++ @wrap_exceptions ++ def gids(self): ++ gid = self._proc_team_info()[team_info_map['gid']] ++ return _common.puids(gid, gid, gid) ++ ++ @wrap_exceptions ++ def cpu_times(self): ++ _user, _kern = self._proc_team_usage_info() ++ return _common.pcputimes(_user, _kern, _user, _kern) ++ ++ @wrap_exceptions ++ def terminal(self): ++ # TODO ++ return None ++ ++ @wrap_exceptions ++ def cwd(self): ++ return None ++ ++ @wrap_exceptions ++ def memory_info(self): ++ # TODO: ++ rss = 0 ++ vms = 0 ++ return pmem(rss, vms) ++ ++ memory_full_info = memory_info ++ ++ @wrap_exceptions ++ def status(self): ++ threads = cext.proc_threads(self.pid) ++ code = threads[0][thread_info_map['state']] ++ # XXX is '?' legit? (we're not supposed to return it anyway) ++ return PROC_STATUSES.get(code, '?') ++ ++ def open_files(self): ++ # TODO: ++ return [] ++ ++ @wrap_exceptions ++ def num_fds(self): ++ # TODO: ++ return None ++ ++ @wrap_exceptions ++ def num_ctx_switches(self): ++ return _common.pctxsw( ++ *cext.proc_num_ctx_switches(self.pid)) ++ ++ @wrap_exceptions ++ def wait(self, timeout=None): ++ return _psposix.wait_pid(self.pid, timeout, self._name) ++ ++ @wrap_exceptions ++ def io_counters(self): ++ return _common.pio( ++ 0, ++ 0, ++ -1, ++ -1) +diff --git a/psutil/_psutil_haiku.cpp b/psutil/_psutil_haiku.cpp +new file mode 100644 +index 0000000..f9b3a44 +--- /dev/null ++++ b/psutil/_psutil_haiku.cpp +@@ -0,0 +1,841 @@ ++/* ++ * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. ++ * Use of this source code is governed by a BSD-style license that can be ++ * found in the LICENSE file. ++ * ++ * macOS platform-specific module methods. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++extern "C" { ++ ++#include "_psutil_common.h" ++#include "_psutil_posix.h" ++//#include "arch/haiku/process_info.h" ++ ++} ++ ++static PyObject *ZombieProcessError; ++ ++ ++/* ++ * Return a Python list of all the PIDs running on the system. ++ */ ++static PyObject * ++psutil_pids(PyObject *self, PyObject *args) { ++ int32 cookie = 0; ++ team_info info; ++ PyObject *py_pid = NULL; ++ PyObject *py_retlist = PyList_New(0); ++ ++ if (py_retlist == NULL) ++ return NULL; ++ ++ while (get_next_team_info(&cookie, &info) == B_OK) { ++ /* quite wasteful: we have all team infos already */ ++ py_pid = Py_BuildValue("i", info.team); ++ if (! py_pid) ++ goto error; ++ if (PyList_Append(py_retlist, py_pid)) ++ goto error; ++ Py_CLEAR(py_pid); ++ } ++ ++ return py_retlist; ++ ++error: ++ Py_XDECREF(py_pid); ++ Py_DECREF(py_retlist); ++ return NULL; ++} ++ ++ ++/* ++ * Return multiple process info as a Python tuple in one shot by ++ * using get_team_info() and filling up a team_info struct. ++ */ ++static PyObject * ++psutil_proc_team_info_oneshot(PyObject *self, PyObject *args) { ++ pid_t pid; ++ team_info info; ++ PyObject *py_name; ++ PyObject *py_retlist; ++ ++ if (! PyArg_ParseTuple(args, "l", &pid)) ++ return NULL; ++ if (get_team_info(pid, &info) != B_OK) ++ return NULL; ++ ++ py_name = PyUnicode_DecodeFSDefault(info.args); ++ if (! py_name) { ++ // Likely a decoding error. We don't want to fail the whole ++ // operation. The python module may retry with proc_name(). ++ PyErr_Clear(); ++ py_name = Py_None; ++ } ++ ++ py_retlist = Py_BuildValue( ++ "lllllO", ++ (long)info.thread_count, // (long) thread_count ++ (long)info.image_count, // (long) image_count ++ (long)info.area_count, // (long) area_count ++ (long)info.uid, // (long) uid ++ (long)info.gid, // (long) gid ++ py_name // (pystr) name ++ ); ++ ++ if (py_retlist != NULL) { ++ // XXX shall we decref() also in case of Py_BuildValue() error? ++ Py_DECREF(py_name); ++ } ++ return py_retlist; ++} ++ ++ ++/* ++ * Return multiple process info as a Python tuple in one shot by ++ * using get_team_usage_info() and filling up a team_usage_info struct. ++ */ ++static PyObject * ++psutil_proc_team_usage_info_oneshot(PyObject *self, PyObject *args) { ++ pid_t pid; ++ team_usage_info info; ++ PyObject *py_retlist; ++ ++ if (! PyArg_ParseTuple(args, "l", &pid)) ++ return NULL; ++ if (get_team_usage_info(pid, B_TEAM_USAGE_SELF, &info) != B_OK) ++ return NULL; ++ ++ py_retlist = Py_BuildValue( ++ "KK", ++ (unsigned long long)info.user_time, ++ (unsigned long long)info.kernel_time ++ ); ++ ++ return py_retlist; ++} ++ ++ ++/* ++ * Return process name from kinfo_proc as a Python string. ++ */ ++static PyObject * ++psutil_proc_name(PyObject *self, PyObject *args) { ++ pid_t pid; ++ team_info info; ++ PyObject *py_name; ++ PyObject *py_retlist; ++ ++ if (! PyArg_ParseTuple(args, "l", &pid)) ++ return NULL; ++ if (get_team_info(pid, &info) != B_OK) ++ return NULL; ++ ++ return PyUnicode_DecodeFSDefault(info.args); ++} ++ ++ ++/* ++ * Return process current working directory. ++ * Raises NSP in case of zombie process. ++ */ ++static PyObject * ++psutil_proc_cwd(PyObject *self, PyObject *args) { ++ /* TODO */ ++ return NULL; ++} ++ ++ ++/* ++ * Return path of the process executable. ++ */ ++static PyObject * ++psutil_proc_exe(PyObject *self, PyObject *args) { ++ pid_t pid; ++ image_info info; ++ int32 cookie = 0; ++ PyObject *py_name; ++ PyObject *py_retlist; ++ ++ if (! PyArg_ParseTuple(args, "l", &pid)) ++ return NULL; ++ while (get_next_image_info(pid, &cookie, &info) == B_OK) { ++ if (info.type != B_APP_IMAGE) ++ continue; ++ return PyUnicode_DecodeFSDefault(info.name); ++ } ++ return NULL; ++} ++ ++ ++/* ++ * Return process cmdline as a Python list of cmdline arguments. ++ */ ++static PyObject * ++psutil_proc_cmdline(PyObject *self, PyObject *args) { ++ return Py_BuildValue("[]"); ++ /* TODO! */ ++ pid_t pid; ++ team_info info; ++ PyObject *py_arg; ++ PyObject *py_retlist = NULL; ++ ++ if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid)) ++ return NULL; ++ if (get_team_info(pid, &info) != B_OK) ++ return NULL; ++ ++ py_retlist = PyList_New(0); ++ if (py_retlist == NULL) ++ return NULL; ++ ++ /* TODO: we can't really differentiate args as we have a single string */ ++ /* TODO: try to split? */ ++ py_arg = PyUnicode_DecodeFSDefault(info.args); ++ if (!py_arg) ++ goto error; ++ if (PyList_Append(py_retlist, py_arg)) ++ goto error; ++ ++ return Py_BuildValue("N", py_retlist); ++ ++error: ++ Py_XDECREF(py_arg); ++ Py_DECREF(py_retlist); ++ return NULL; ++} ++ ++ ++/* ++ * Return process environment as a Python string. ++ */ ++static PyObject * ++psutil_proc_environ(PyObject *self, PyObject *args) { ++ /* TODO: likely impossible */ ++ return NULL; ++} ++ ++ ++/* ++ * Return the number of logical CPUs in the system. ++ */ ++static PyObject * ++psutil_cpu_count_logical(PyObject *self, PyObject *args) { ++ /* TODO:get_cpu_topology_info */ ++ return NULL; ++} ++ ++ ++/* ++ * Return the number of physical CPUs in the system. ++ */ ++static PyObject * ++psutil_cpu_count_phys(PyObject *self, PyObject *args) { ++ /* TODO:get_cpu_topology_info */ ++ return NULL; ++} ++ ++ ++/* ++ * Returns the USS (unique set size) of the process. Reference: ++ * https://dxr.mozilla.org/mozilla-central/source/xpcom/base/ ++ * nsMemoryReporterManager.cpp ++ */ ++static PyObject * ++psutil_proc_memory_uss(PyObject *self, PyObject *args) { ++ /* TODO */ ++ return NULL; ++} ++ ++ ++/* ++ * Return system virtual memory stats. ++ * See: ++ * https://opensource.apple.com/source/system_cmds/system_cmds-790/ ++ * vm_stat.tproj/vm_stat.c.auto.html ++ */ ++static PyObject * ++psutil_virtual_mem(PyObject *self, PyObject *args) { ++ system_info info; ++ status_t ret; ++ int pagesize = getpagesize(); ++ ++ ++ ret = get_system_info(&info); ++ if (ret != B_OK) { ++ PyErr_Format( ++ PyExc_RuntimeError, "get_system_info() syscall failed: %s", ++ strerror(ret)); ++ return NULL; ++ } ++ ++ return Py_BuildValue( ++ "KKKKKKK", ++ (unsigned long long) info.max_pages * pagesize, // total ++ (unsigned long long) info.used_pages * pagesize, // used ++ (unsigned long long) info.cached_pages * pagesize, // cached ++ (unsigned long long) info.block_cache_pages * pagesize, // buffers ++ (unsigned long long) info.ignored_pages * pagesize, // ignored ++ (unsigned long long) info.needed_memory, // needed ++ (unsigned long long) info.free_memory // available ++ ); ++} ++ ++ ++/* ++ * Return stats about swap memory. ++ */ ++static PyObject * ++psutil_swap_mem(PyObject *self, PyObject *args) { ++ system_info info; ++ status_t ret; ++ int pagesize = getpagesize(); ++ ++ ++ ret = get_system_info(&info); ++ if (ret != B_OK) { ++ PyErr_Format( ++ PyExc_RuntimeError, "get_system_info() syscall failed: %s", ++ strerror(ret)); ++ return NULL; ++ } ++ ++ return Py_BuildValue( ++ "KK", ++ (unsigned long long) info.max_swap_pages * pagesize, ++ (unsigned long long) info.free_swap_pages * pagesize); ++ /* XXX: .page_faults? */ ++} ++ ++ ++/* ++ * Return a Python tuple representing user, kernel and idle CPU times ++ */ ++static PyObject * ++psutil_cpu_times(PyObject *self, PyObject *args) { ++ system_info info; ++ status_t ret; ++ int pagesize = getpagesize(); ++ ++ ret = get_system_info(&info); ++ if (ret != B_OK) { ++ PyErr_Format( ++ PyExc_RuntimeError, "get_system_info() syscall failed: %s", ++ strerror(ret)); ++ return NULL; ++ } ++ ++ cpu_info cpus[info.cpu_count]; ++ ++ ret = get_cpu_info(0, info.cpu_count, cpus); ++ if (ret != B_OK) { ++ PyErr_Format( ++ PyExc_RuntimeError, "get_cpu_info() syscall failed: %s", ++ strerror(ret)); ++ return NULL; ++ } ++ ++ /* TODO */ ++ return Py_BuildValue( ++ "(dddd)", ++ (double)0.0, ++ (double)0.0, ++ (double)0.0, ++ (double)0.0 ++ ); ++} ++ ++ ++/* ++ * Return a Python list of tuple representing per-cpu times ++ */ ++static PyObject * ++psutil_per_cpu_times(PyObject *self, PyObject *args) { ++ system_info info; ++ status_t ret; ++ uint32 i, pagesize = getpagesize(); ++ PyObject *py_retlist = PyList_New(0); ++ PyObject *py_cputime = NULL; ++ ++ ret = get_system_info(&info); ++ if (ret != B_OK) { ++ PyErr_Format( ++ PyExc_RuntimeError, "get_system_info() syscall failed: %s", ++ strerror(ret)); ++ return NULL; ++ } ++ ++ cpu_info cpus[info.cpu_count]; ++ ++ ret = get_cpu_info(0, info.cpu_count, cpus); ++ if (ret != B_OK) { ++ PyErr_Format( ++ PyExc_RuntimeError, "get_cpu_info() syscall failed: %s", ++ strerror(ret)); ++ return NULL; ++ } ++ ++ /* TODO: check idle thread times? */ ++ ++ for (i = 0; i < info.cpu_count; i++) { ++ py_cputime = Py_BuildValue( ++ "(dddd)", ++ (double)0.0, ++ (double)0.0, ++ (double)0.0, ++ (double)0.0 ++ ); ++ if (!py_cputime) ++ goto error; ++ if (PyList_Append(py_retlist, py_cputime)) ++ goto error; ++ Py_CLEAR(py_cputime); ++ } ++ return py_retlist; ++ ++error: ++ Py_XDECREF(py_cputime); ++ Py_DECREF(py_retlist); ++ return NULL; ++} ++ ++ ++/* ++ * Retrieve CPU frequency. ++ */ ++static PyObject * ++psutil_cpu_freq(PyObject *self, PyObject *args) { ++ status_t ret; ++ uint32 i, topologyNodeCount = 0; ++ ret = get_cpu_topology_info(NULL, &topologyNodeCount); ++ if (ret != B_OK || topologyNodeCount == 0) ++ return NULL; ++ cpu_topology_node_info topology[topologyNodeCount]; ++ ret = get_cpu_topology_info(topology, &topologyNodeCount); ++ ++ for (i = 0; i < topologyNodeCount; i++) { ++ if (topology[i].type == B_TOPOLOGY_CORE) ++ /* TODO: find min / max? */ ++ return Py_BuildValue( ++ "KKK", ++ topology[i].data.core.default_frequency, ++ topology[i].data.core.default_frequency, ++ topology[i].data.core.default_frequency); ++ } ++ ++ return NULL; ++} ++ ++ ++/* ++ * Return a Python float indicating the system boot time expressed in ++ * seconds since the epoch. ++ */ ++static PyObject * ++psutil_boot_time(PyObject *self, PyObject *args) { ++ system_info info; ++ status_t ret; ++ int pagesize = getpagesize(); ++ ++ ret = get_system_info(&info); ++ if (ret != B_OK) { ++ PyErr_Format( ++ PyExc_RuntimeError, "get_system_info() syscall failed: %s", ++ strerror(ret)); ++ return NULL; ++ } ++ ++ return Py_BuildValue("f", (float)info.boot_time / 1000000.0); ++} ++ ++ ++/* ++ * Return a list of tuples including device, mount point and fs type ++ * for all partitions mounted on the system. ++ */ ++static PyObject * ++psutil_disk_partitions(PyObject *self, PyObject *args) { ++ int32 cookie = 0; ++ dev_t dev; ++ fs_info info; ++ uint32 flags; ++ BString opts; ++ PyObject *py_dev = NULL; ++ PyObject *py_mountp = NULL; ++ PyObject *py_tuple = NULL; ++ PyObject *py_retlist = PyList_New(0); ++ ++ if (py_retlist == NULL) ++ return NULL; ++ ++ while ((dev = next_dev(&cookie)) >= 0) { ++ opts = ""; ++ if (fs_stat_dev(dev, &info) != B_OK) ++ continue; ++ flags = info.flags; ++ ++ // see fs_info.h ++ if (flags & B_FS_IS_READONLY) ++ opts << "ro"; ++ else ++ opts << "rw"; ++ // TODO ++ if (flags & B_FS_IS_REMOVABLE) ++ opts << ",removable"; ++ if (flags & B_FS_IS_PERSISTENT) ++ opts << ",persistent"; ++ if (flags & B_FS_IS_SHARED) ++ opts << ",shared"; ++ if (flags & B_FS_HAS_MIME) ++ opts << ",has_mime"; ++ if (flags & B_FS_HAS_ATTR) ++ opts << ",has_attr"; ++ if (flags & B_FS_HAS_QUERY) ++ opts << ",has_query"; ++ if (flags & B_FS_HAS_SELF_HEALING_LINKS) ++ opts << ",has_self_healing_links"; ++ if (flags & B_FS_HAS_ALIASES) ++ opts << ",has_aliases"; ++ if (flags & B_FS_SUPPORTS_NODE_MONITORING) ++ opts << ",has_node_monitoring"; ++ if (flags & B_FS_SUPPORTS_MONITOR_CHILDREN) ++ opts << ",cmdflags"; ++ ++ py_dev = PyUnicode_DecodeFSDefault(info.device_name); ++ if (! py_dev) ++ goto error; ++ py_mountp = PyUnicode_DecodeFSDefault(info.volume_name); ++ if (! py_mountp) ++ goto error; ++ py_tuple = Py_BuildValue( ++ "(OOss)", ++ py_dev, // device ++ py_mountp, // mount point ++ info.fsh_name, // fs type ++ opts.String()); // options ++ if (!py_tuple) ++ goto error; ++ if (PyList_Append(py_retlist, py_tuple)) ++ goto error; ++ Py_CLEAR(py_dev); ++ Py_CLEAR(py_mountp); ++ Py_CLEAR(py_tuple); ++ } ++ ++ return py_retlist; ++ ++error: ++ Py_XDECREF(py_dev); ++ Py_XDECREF(py_mountp); ++ Py_XDECREF(py_tuple); ++ Py_DECREF(py_retlist); ++ return NULL; ++} ++ ++ ++/* ++ * Return process threads ++ */ ++static PyObject * ++psutil_proc_threads(PyObject *self, PyObject *args) { ++ pid_t pid; ++ int32 cookie = 0; ++ thread_info info; ++ int err, ret; ++ PyObject *py_tuple = NULL; ++ PyObject *py_retlist = PyList_New(0); ++ ++ if (py_retlist == NULL) ++ return NULL; ++ ++ if (! PyArg_ParseTuple(args, "l", &pid)) ++ goto error; ++ ++ while (get_next_thread_info(pid, &cookie, &info) == B_OK) { ++ py_tuple = Py_BuildValue( ++ "Iffl", ++ info.thread, ++ (float)info.user_time / 1000000.0, ++ (float)info.kernel_time / 1000000.0, ++ (long)info.state ++ //XXX: priority, ? ++ ); ++ if (!py_tuple) ++ goto error; ++ if (PyList_Append(py_retlist, py_tuple)) ++ goto error; ++ Py_CLEAR(py_tuple); ++ } ++ ++ return py_retlist; ++ ++error: ++ Py_XDECREF(py_tuple); ++ Py_DECREF(py_retlist); ++ return NULL; ++} ++ ++ ++/* ++ * Return process open files as a Python tuple. ++ * References: ++ * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/m78fd ++ * - /usr/include/sys/proc_info.h ++ */ ++static PyObject * ++psutil_proc_open_files(PyObject *self, PyObject *args) { ++ /* TODO */ ++ return NULL; ++} ++ ++ ++/* ++ * Return process TCP and UDP connections as a list of tuples. ++ * Raises NSP in case of zombie process. ++ * References: ++ * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/wNrC0 ++ * - /usr/include/sys/proc_info.h ++ */ ++static PyObject * ++psutil_proc_connections(PyObject *self, PyObject *args) { ++ /* TODO */ ++ return NULL; ++} ++ ++ ++/* ++ * Return number of file descriptors opened by process. ++ * Raises NSP in case of zombie process. ++ */ ++static PyObject * ++psutil_proc_num_fds(PyObject *self, PyObject *args) { ++ /* TODO */ ++ return NULL; ++} ++ ++ ++/* ++ * Return a Python list of named tuples with overall network I/O information ++ */ ++static PyObject * ++psutil_net_io_counters(PyObject *self, PyObject *args) { ++ /* TODO */ ++ return NULL; ++} ++ ++ ++/* ++ * Return a Python dict of tuples for disk I/O information ++ */ ++static PyObject * ++psutil_disk_io_counters(PyObject *self, PyObject *args) { ++ /* TODO */ ++ return NULL; ++} ++ ++ ++/* ++ * Return currently connected users as a list of tuples. ++ */ ++static PyObject * ++psutil_users(PyObject *self, PyObject *args) { ++ /* TODO */ ++ return NULL; ++} ++ ++ ++/* ++ * Return CPU statistics. ++ */ ++static PyObject * ++psutil_cpu_stats(PyObject *self, PyObject *args) { ++ /* TODO */ ++ return NULL; ++} ++ ++ ++/* ++ * Return battery information. ++ */ ++static PyObject * ++psutil_sensors_battery(PyObject *self, PyObject *args) { ++ /* TODO */ ++ return NULL; ++} ++ ++ ++/* ++ * define the psutil C module methods and initialize the module. ++ */ ++static PyMethodDef mod_methods[] = { ++ // --- per-process functions ++ ++ {"proc_team_info_oneshot", psutil_proc_team_info_oneshot, METH_VARARGS, ++ "Return multiple process info."}, ++ {"proc_team_usage_info_oneshot", psutil_proc_team_usage_info_oneshot, METH_VARARGS, ++ "Return multiple process info."}, ++ {"proc_name", psutil_proc_name, METH_VARARGS, ++ "Return process name"}, ++ {"proc_cmdline", psutil_proc_cmdline, METH_VARARGS, ++ "Return process cmdline as a list of cmdline arguments"}, ++ {"proc_environ", psutil_proc_environ, METH_VARARGS, ++ "Return process environment data"}, ++ {"proc_exe", psutil_proc_exe, METH_VARARGS, ++ "Return path of the process executable"}, ++ {"proc_cwd", psutil_proc_cwd, METH_VARARGS, ++ "Return process current working directory."}, ++ {"proc_memory_uss", psutil_proc_memory_uss, METH_VARARGS, ++ "Return process USS memory"}, ++ {"proc_threads", psutil_proc_threads, METH_VARARGS, ++ "Return process threads as a list of tuples"}, ++ {"proc_open_files", psutil_proc_open_files, METH_VARARGS, ++ "Return files opened by process as a list of tuples"}, ++ {"proc_num_fds", psutil_proc_num_fds, METH_VARARGS, ++ "Return the number of fds opened by process."}, ++ {"proc_connections", psutil_proc_connections, METH_VARARGS, ++ "Get process TCP and UDP connections as a list of tuples"}, ++ ++ // --- system-related functions ++ ++ {"pids", psutil_pids, METH_VARARGS, ++ "Returns a list of PIDs currently running on the system"}, ++ {"cpu_count_logical", psutil_cpu_count_logical, METH_VARARGS, ++ "Return number of logical CPUs on the system"}, ++ {"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS, ++ "Return number of physical CPUs on the system"}, ++ {"virtual_mem", psutil_virtual_mem, METH_VARARGS, ++ "Return system virtual memory stats"}, ++ {"swap_mem", psutil_swap_mem, METH_VARARGS, ++ "Return stats about swap memory, in bytes"}, ++ {"cpu_times", psutil_cpu_times, METH_VARARGS, ++ "Return system cpu times as a tuple (user, system, nice, idle, irc)"}, ++ {"per_cpu_times", psutil_per_cpu_times, METH_VARARGS, ++ "Return system per-cpu times as a list of tuples"}, ++ {"cpu_freq", psutil_cpu_freq, METH_VARARGS, ++ "Return cpu current frequency"}, ++ {"boot_time", psutil_boot_time, METH_VARARGS, ++ "Return the system boot time expressed in seconds since the epoch."}, ++ {"disk_partitions", psutil_disk_partitions, METH_VARARGS, ++ "Return a list of tuples including device, mount point and " ++ "fs type for all partitions mounted on the system."}, ++ {"net_io_counters", psutil_net_io_counters, METH_VARARGS, ++ "Return dict of tuples of networks I/O information."}, ++ {"disk_io_counters", psutil_disk_io_counters, METH_VARARGS, ++ "Return dict of tuples of disks I/O information."}, ++ {"users", psutil_users, METH_VARARGS, ++ "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 ++ {"set_testing", psutil_set_testing, METH_NOARGS, ++ "Set psutil in testing mode"}, ++ ++ {NULL, NULL, 0, NULL} ++}; ++ ++ ++#if PY_MAJOR_VERSION >= 3 ++ #define INITERR return NULL ++ ++ static struct PyModuleDef moduledef = { ++ PyModuleDef_HEAD_INIT, ++ "_psutil_haiku", ++ NULL, ++ -1, ++ mod_methods, ++ NULL, ++ NULL, ++ NULL, ++ NULL ++ }; ++ ++extern "C" PyObject *PyInit__psutil_haiku(void); ++ ++ PyObject *PyInit__psutil_haiku(void) ++#else /* PY_MAJOR_VERSION */ ++ #define INITERR return ++ ++extern "C" void init_psutil_haiku(void); ++ ++ void init_psutil_haiku(void) ++#endif /* PY_MAJOR_VERSION */ ++{ ++#if PY_MAJOR_VERSION >= 3 ++ PyObject *mod = PyModule_Create(&moduledef); ++#else ++ PyObject *mod = Py_InitModule("_psutil_haiku", mod_methods); ++#endif ++ if (mod == NULL) ++ INITERR; ++ ++ if (psutil_setup() != 0) ++ INITERR; ++ ++ if (PyModule_AddIntConstant(mod, "version", PSUTIL_VERSION)) ++ INITERR; ++ // process status constants, defined in: ++ // headers/os/kernel/OS.h ++ if (PyModule_AddIntConstant(mod, "B_THREAD_RUNNING", B_THREAD_RUNNING)) ++ INITERR; ++ if (PyModule_AddIntConstant(mod, "B_THREAD_READY", B_THREAD_READY)) ++ INITERR; ++ if (PyModule_AddIntConstant(mod, "B_THREAD_RECEIVING", B_THREAD_RECEIVING)) ++ INITERR; ++ if (PyModule_AddIntConstant(mod, "B_THREAD_ASLEEP", B_THREAD_ASLEEP)) ++ INITERR; ++ if (PyModule_AddIntConstant(mod, "B_THREAD_SUSPENDED", B_THREAD_SUSPENDED)) ++ INITERR; ++ if (PyModule_AddIntConstant(mod, "B_THREAD_WAITING", B_THREAD_WAITING)) ++ INITERR; ++ // connection status constants ++/*XXX: ++ if (PyModule_AddIntConstant(mod, "TCPS_CLOSED", TCPS_CLOSED)) ++ INITERR; ++ if (PyModule_AddIntConstant(mod, "TCPS_CLOSING", TCPS_CLOSING)) ++ INITERR; ++ if (PyModule_AddIntConstant(mod, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT)) ++ INITERR; ++ if (PyModule_AddIntConstant(mod, "TCPS_LISTEN", TCPS_LISTEN)) ++ INITERR; ++ if (PyModule_AddIntConstant(mod, "TCPS_ESTABLISHED", TCPS_ESTABLISHED)) ++ INITERR; ++ if (PyModule_AddIntConstant(mod, "TCPS_SYN_SENT", TCPS_SYN_SENT)) ++ INITERR; ++ if (PyModule_AddIntConstant(mod, "TCPS_SYN_RECEIVED", TCPS_SYN_RECEIVED)) ++ INITERR; ++ if (PyModule_AddIntConstant(mod, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1)) ++ INITERR; ++ if (PyModule_AddIntConstant(mod, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2)) ++ INITERR; ++ if (PyModule_AddIntConstant(mod, "TCPS_LAST_ACK", TCPS_LAST_ACK)) ++ INITERR; ++ if (PyModule_AddIntConstant(mod, "TCPS_TIME_WAIT", TCPS_TIME_WAIT)) ++ INITERR; ++*/ ++ if (PyModule_AddIntConstant(mod, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE)) ++ INITERR; ++ ++ if (mod == NULL) ++ INITERR; ++#if PY_MAJOR_VERSION >= 3 ++ return mod; ++#endif ++} +diff --git a/psutil/_psutil_posix.c b/psutil/_psutil_posix.c +index aa60084..8165475 100644 +--- a/psutil/_psutil_posix.c ++++ b/psutil/_psutil_posix.c +@@ -40,6 +40,9 @@ + #include + #elif defined(PSUTIL_AIX) + #include ++#elif defined(PSUTIL_HAIKU) ++ #include ++ #include + #endif + + #include "_psutil_common.h" +@@ -675,7 +678,7 @@ static PyMethodDef mod_methods[] = { + if (mod == NULL) + INITERR; + +-#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX) || defined(PSUTIL_SUNOS) || defined(PSUTIL_AIX) ++#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX) || defined(PSUTIL_SUNOS) || defined(PSUTIL_AIX) || defined(PSUTIL_HAIKU) + if (PyModule_AddIntConstant(mod, "AF_LINK", AF_LINK)) INITERR; + #endif + +diff --git a/setup.py b/setup.py +index 99818ad..8b81d25 100755 +--- a/setup.py ++++ b/setup.py +@@ -32,6 +32,7 @@ sys.path.insert(0, os.path.join(HERE, "psutil")) + from _common import AIX # NOQA + from _common import BSD # NOQA + from _common import FREEBSD # NOQA ++from _common import HAIKU # NOQA + from _common import LINUX # NOQA + from _common import MACOS # NOQA + from _common import NETBSD # NOQA +@@ -256,6 +257,16 @@ elif AIX: + libraries=['perfstat'], + define_macros=macros) + ++elif HAIKU: ++ macros.append(("PSUTIL_HAIKU", 1)) ++ macros.append(("_DEFAULT_SOURCE", 1)) ++ ext = Extension( ++ 'psutil._psutil_haiku', ++ sources=sources + [ ++ 'psutil/_psutil_haiku.cpp'], ++ libraries=['be', 'network'], ++ define_macros=macros) ++ + else: + sys.exit('platform %s is not supported' % sys.platform) + +-- +2.24.1 + diff --git a/dev-python/psutil/psutil-5.6.7.recipe b/dev-python/psutil/psutil-5.6.7.recipe new file mode 100644 index 000000000..e00ed4b6c --- /dev/null +++ b/dev-python/psutil/psutil-5.6.7.recipe @@ -0,0 +1,71 @@ +SUMMARY="Cross-platform lib for process and system monitoring in Python" +DESCRIPTION="psutil (process and system utilities) is a cross-platform library +for retrieving information on running processes and system utilization +(CPU, memory, disks, network, sensors) in Python. +It is useful mainly for system monitoring, profiling and limiting process +resources and management of running processes. +It implements many functionalities offered by classic UNIX command line +tools such as ps, top, iotop, lsof, netstat, ifconfig, free and others." +HOMEPAGE="https://github.com/giampaolo/psutil/" +COPYRIGHT="2009 Giampaolo Rodola'" +LICENSE="BSD (3-clause)" +REVISION="1" +SOURCE_URI="https://github.com/giampaolo/psutil/archive/release-$portVersion.tar.gz" +CHECKSUM_SHA256="ebbed18bf912fa4981d05c5c1a0cacec2aa8c594e1608f0cf5cc7a3d4f63d4d4" +SOURCE_DIR="psutil-release-$portVersion" +PATCHES="psutil-$portVersion.patchset" + +ARCHITECTURES="!x86_gcc2 ?x86_64" +SECONDARY_ARCHITECTURES="?x86" + +PROVIDES=" + $portName = $portVersion + " +REQUIRES=" + haiku$secondaryArchSuffix + " + +BUILD_REQUIRES=" + haiku${secondaryArchSuffix}_devel + " + +BUILD_PREREQUIRES=" + cmd:gcc$secondaryArchSuffix + " + +PYTHON_PACKAGES=(python36 python3) +PYTHON_VERSIONS=(3.6 3.7) +for i in "${!PYTHON_PACKAGES[@]}"; do +pythonPackage=${PYTHON_PACKAGES[i]} +pythonVersion=${PYTHON_VERSIONS[$i]} +eval "PROVIDES_${pythonPackage}=\"\ + ${portName}_$pythonPackage = $portVersion\ + \"; \ +REQUIRES_$pythonPackage=\"\ + haiku$secondaryArchSuffix\n\ + cmd:python$pythonVersion\ + \"" +BUILD_REQUIRES="$BUILD_REQUIRES + setuptools_$pythonPackage" +BUILD_PREREQUIRES="$BUILD_PREREQUIRES + cmd:python$pythonVersion" +done + +INSTALL() +{ + for i in "${!PYTHON_PACKAGES[@]}"; do + pythonPackage=${PYTHON_PACKAGES[i]} + pythonVersion=${PYTHON_VERSIONS[$i]} + + python=python$pythonVersion + installLocation=$prefix/lib/$python/vendor-packages/ + export PYTHONPATH=$installLocation:$PYTHONPATH + mkdir -p $installLocation + rm -rf build + $python setup.py build install \ + --root=/ --prefix=$prefix + + packageEntries $pythonPackage \ + $prefix/lib/python* + done +}