mirror of
https://github.com/yann64/haikuports.git
synced 2026-04-09 05:10:05 +02:00
1411 lines
39 KiB
Plaintext
1411 lines
39 KiB
Plaintext
From cad8406514db2b2241d0e522ede4d19267c8e441 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= <revol@free.fr>
|
|
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 <Python.h>
|
|
+#include <assert.h>
|
|
+#include <errno.h>
|
|
+#include <stdbool.h>
|
|
+#include <stdlib.h>
|
|
+#include <stdio.h>
|
|
+#include <arpa/inet.h>
|
|
+#include <net/if_dl.h>
|
|
+#include <pwd.h>
|
|
+
|
|
+#include <fs_info.h>
|
|
+#include <image.h>
|
|
+#include <OS.h>
|
|
+#include <String.h>
|
|
+
|
|
+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 <sys/sockio.h>
|
|
#elif defined(PSUTIL_AIX)
|
|
#include <netdb.h>
|
|
+#elif defined(PSUTIL_HAIKU)
|
|
+ #include <netdb.h>
|
|
+ #include <sys/sockio.h>
|
|
#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
|
|
|