summaryrefslogtreecommitdiff
path: root/src/haiku.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/haiku.c')
-rw-r--r--src/haiku.c286
1 files changed, 286 insertions, 0 deletions
diff --git a/src/haiku.c b/src/haiku.c
new file mode 100644
index 00000000000..485d86983c2
--- /dev/null
+++ b/src/haiku.c
@@ -0,0 +1,286 @@
+/* Haiku subroutines that are general to the Haiku operating system.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "lisp.h"
+#include "process.h"
+#include "coding.h"
+
+#include <kernel/OS.h>
+
+#include <pwd.h>
+#include <stdlib.h>
+
+Lisp_Object
+list_system_processes (void)
+{
+ team_info info;
+ int32 cookie = 0;
+ Lisp_Object lval = Qnil;
+
+ while (get_next_team_info (&cookie, &info) == B_OK)
+ lval = Fcons (make_fixnum (info.team), lval);
+
+ return lval;
+}
+
+Lisp_Object
+system_process_attributes (Lisp_Object pid)
+{
+ CHECK_FIXNUM (pid);
+
+ team_info info;
+ Lisp_Object lval = Qnil;
+ thread_info inf;
+ area_info area;
+ team_id id = (team_id) XFIXNUM (pid);
+ struct passwd *g;
+ size_t mem = 0;
+
+ if (get_team_info (id, &info) != B_OK)
+ return Qnil;
+
+ bigtime_t everything = 0, vsample = 0;
+ bigtime_t cpu_eaten = 0, esample = 0;
+
+ lval = Fcons (Fcons (Qeuid, make_fixnum (info.uid)), lval);
+ lval = Fcons (Fcons (Qegid, make_fixnum (info.gid)), lval);
+ lval = Fcons (Fcons (Qthcount, make_fixnum (info.thread_count)), lval);
+ lval = Fcons (Fcons (Qcomm, build_string_from_utf8 (info.args)), lval);
+
+ g = getpwuid (info.uid);
+
+ if (g && g->pw_name)
+ lval = Fcons (Fcons (Quser, build_string (g->pw_name)), lval);
+
+ /* FIXME: Calculating this makes Emacs show up as using 100% CPU! */
+
+ for (int32 team_cookie = 0;
+ get_next_team_info (&team_cookie, &info) == B_OK;)
+ for (int32 thread_cookie = 0;
+ get_next_thread_info (info.team, &thread_cookie, &inf) == B_OK;)
+ {
+ if (inf.team == id && strncmp (inf.name, "idle thread ", 12))
+ cpu_eaten += inf.user_time + inf.kernel_time;
+ everything += inf.user_time + inf.kernel_time;
+ }
+
+ sleep (0.05);
+
+ for (int32 team_cookie = 0;
+ get_next_team_info (&team_cookie, &info) == B_OK;)
+ for (int32 thread_cookie = 0;
+ get_next_thread_info (info.team, &thread_cookie, &inf) == B_OK;)
+ {
+ if (inf.team == id && strncmp (inf.name, "idle thread ", 12))
+ esample += inf.user_time + inf.kernel_time;
+ vsample += inf.user_time + inf.kernel_time;
+ }
+
+ cpu_eaten = esample - cpu_eaten;
+ everything = vsample - everything;
+
+ if (everything)
+ lval = Fcons (Fcons (Qpcpu, make_float (((double) (cpu_eaten) /
+ (double) (everything)) * 100)),
+ lval);
+ else
+ lval = Fcons (Fcons (Qpcpu, make_float (0.0)), lval);
+
+ for (ssize_t area_cookie = 0;
+ get_next_area_info (id, &area_cookie, &area) == B_OK;)
+ mem += area.ram_size;
+
+ system_info sinfo;
+ get_system_info (&sinfo);
+ int64 max = (int64) sinfo.max_pages * B_PAGE_SIZE;
+
+ lval = Fcons (Fcons (Qpmem, make_float (((double) mem /
+ (double) max) * 100)),
+ lval);
+ lval = Fcons (Fcons (Qrss, make_fixnum (mem / 1024)), lval);
+
+ return lval;
+}
+
+
+/* Borrowed from w32 implementation. */
+
+struct load_sample
+{
+ time_t sample_time;
+ bigtime_t idle;
+ bigtime_t kernel;
+ bigtime_t user;
+};
+
+/* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
+static struct load_sample samples[16*60];
+static int first_idx = -1, last_idx = -1;
+static int max_idx = ARRAYELTS (samples);
+static unsigned num_of_processors = 0;
+
+static int
+buf_next (int from)
+{
+ int next_idx = from + 1;
+
+ if (next_idx >= max_idx)
+ next_idx = 0;
+
+ return next_idx;
+}
+
+static int
+buf_prev (int from)
+{
+ int prev_idx = from - 1;
+
+ if (prev_idx < 0)
+ prev_idx = max_idx - 1;
+
+ return prev_idx;
+}
+
+static double
+getavg (int which)
+{
+ double retval = -1.0;
+ double tdiff;
+ int idx;
+ double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
+ time_t now = samples[last_idx].sample_time;
+
+ if (first_idx != last_idx)
+ {
+ for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
+ {
+ tdiff = difftime (now, samples[idx].sample_time);
+ if (tdiff >= span - 2 * DBL_EPSILON * now)
+ {
+ long double sys =
+ (samples[last_idx].kernel + samples[last_idx].user) -
+ (samples[idx].kernel + samples[idx].user);
+ long double idl = samples[last_idx].idle - samples[idx].idle;
+
+ retval = (idl / (sys + idl)) * num_of_processors;
+ break;
+ }
+ if (idx == first_idx)
+ break;
+ }
+ }
+
+ return retval;
+}
+
+static void
+sample_sys_load (bigtime_t *idle, bigtime_t *system, bigtime_t *user)
+{
+ bigtime_t i = 0, s = 0, u = 0;
+ team_info info;
+ thread_info inf;
+
+ for (int32 team_cookie = 0;
+ get_next_team_info (&team_cookie, &info) == B_OK;)
+ for (int32 thread_cookie = 0;
+ get_next_thread_info (info.team, &thread_cookie, &inf) == B_OK;)
+ {
+ if (!strncmp (inf.name, "idle thread ", 12))
+ i += inf.user_time + inf.kernel_time;
+ else
+ s += inf.kernel_time, u += inf.user_time;
+ }
+
+ *idle = i;
+ *system = s;
+ *user = u;
+}
+
+int
+getloadavg (double loadavg[], int nelem)
+{
+ int elem;
+ bigtime_t idle, kernel, user;
+ time_t now = time (NULL);
+
+ if (num_of_processors <= 0)
+ {
+ system_info i;
+ if (get_system_info (&i) == B_OK)
+ num_of_processors = i.cpu_count;
+ }
+
+ /* If system time jumped back for some reason, delete all samples
+ whose time is later than the current wall-clock time. This
+ prevents load average figures from becoming frozen for prolonged
+ periods of time, when system time is reset backwards. */
+ if (last_idx >= 0)
+ {
+ while (difftime (now, samples[last_idx].sample_time) < -1.0)
+ {
+ if (last_idx == first_idx)
+ {
+ first_idx = last_idx = -1;
+ break;
+ }
+ last_idx = buf_prev (last_idx);
+ }
+ }
+
+ /* Store another sample. We ignore samples that are less than 1 sec
+ apart. */
+ if (last_idx < 0
+ || (difftime (now, samples[last_idx].sample_time)
+ >= 1.0 - 2 * DBL_EPSILON * now))
+ {
+ sample_sys_load (&idle, &kernel, &user);
+ last_idx = buf_next (last_idx);
+ samples[last_idx].sample_time = now;
+ samples[last_idx].idle = idle;
+ samples[last_idx].kernel = kernel;
+ samples[last_idx].user = user;
+ /* If the buffer has more that 15 min worth of samples, discard
+ the old ones. */
+ if (first_idx == -1)
+ first_idx = last_idx;
+ while (first_idx != last_idx
+ && (difftime (now, samples[first_idx].sample_time)
+ >= 15.0 * 60 + 2 * DBL_EPSILON * now))
+ first_idx = buf_next (first_idx);
+ }
+
+ for (elem = 0; elem < nelem; elem++)
+ {
+ double avg = getavg (elem);
+
+ if (avg < 0)
+ break;
+ loadavg[elem] = avg;
+ }
+
+ /* Always return at least one element, otherwise load-average
+ returns nil, and Lisp programs might decide we cannot measure
+ system load. For example, jit-lock-stealth-load's defcustom
+ might decide that feature is "unsupported". */
+ if (elem == 0)
+ loadavg[elem++] = 0.09; /* < display-time-load-average-threshold */
+
+ return elem;
+}