From X512 <danger_mail@xxxxxxx>:
X512 has uploaded this change for review. (
https://review.haiku-os.org/c/haiku/+/3634 ;)
Change subject: iotop: Add an iotop utility
......................................................................
iotop: Add an iotop utility
iotop is a simple top like utility for monitoring IOs. For utility to
work, kernel must do IO accounting for each process. The patch adds
struct io_accounting in the kernel account for IOs performed by each
process.
The accounting for IO is performed in various version of read and
write system calls.
The userland part (iotop command) uses team_info mechanism to get
the accounting information in the userland. The utility provides user
with lots of options like
- monitoring processes of particular user
- monitoring processes based on process ids
- only showing processes doing actual IOs
- configuration refreshing delay
iotop also allows user to sort the output on various parameters
dynamically while running.
The utility also checks the visible terminal co-ordinates and updates
the output accordingly.
Here is a sample output of the iotop:
~> ./iotop
Total Disk Reads: 2.00 B/s | Total Disk Writes: 0.00 B/s
TID USER READ BW WRITE BW IO % Command
114 user 2.00 B/s 0.00 B/s 100.00 %
/boot/system/servers/power_daemon
48 user 0.00 B/s 0.00 B/s 0.00 %
/boot/system/servers/registrar
55 user 0.00 B/s 0.00 B/s 0.00 %
/boot/system/servers/debug_server
56 user 0.00 B/s 0.00 B/s 0.00 %
/boot/system/servers/net_server
57 user 0.00 B/s 0.00 B/s 0.00 %
/boot/system/servers/app_server
72 user 0.00 B/s 0.00 B/s 0.00 %
/boot/system/servers/syslog_daemon
84 user 0.00 B/s 0.00 B/s 0.00 %
/boot/system/servers/input_server
94 user 0.00 B/s 0.00 B/s 0.00 %
/boot/system/servers/mount_server
106 user 0.00 B/s 0.00 B/s 0.00 % /boot/system/Tracker
107 user 0.00 B/s 0.00 B/s 0.00 % /boot/system/Deskbar
108 user 0.00 B/s 0.00 B/s 0.00 %
/boot/system/servers/media_server
109 user 0.00 B/s 0.00 B/s 0.00 %
/boot/system/servers/midi_server
110 user 0.00 B/s 0.00 B/s 0.00 %
/boot/system/servers/print_server
112 user 0.00 B/s 0.00 B/s 0.00 %
/boot/system/servers/cddb_daemon
113 user 0.00 B/s 0.00 B/s 0.00 %
/boot/system/servers/notification_server
143 user 0.00 B/s 0.00 B/s 0.00 %
/boot/system/servers/media_addon_server
193 user 0.00 B/s 0.00 B/s 0.00 % /boot/system/apps/Terminal
197 user 0.00 B/s 0.00 B/s 0.00 % /bin/bash -l
1 user 0.00 B/s 0.00 B/s 0.00 % kernel_team
212 user 0.00 B/s 0.00 B/s 0.00 % ./iotop
-----------------------------------------------------------------------
User: all
Processes: all
Sorted according to 'Percentage of total IOs'. Reverse Sorting: false
Refreshing every 3 seconds.
~> ./iotop -o
Total Disk Reads: 2.00 B/s | Total Disk Writes: 0.00 B/s
TID USER READ BW WRITE BW IO % Command
114 user 2.00 B/s 0.00 B/s 100.00 %
/boot/system/servers/power_daemon
-----------------------------------------------------------------------
User: all
Processes: all
Only showing processes doing IOs.
Sorted according to 'Percentage of total IOs'. Reverse Sorting: false
Refreshing every 3 seconds.
Signed-off-by: Prasad Joshi <prasadjoshi.linux@xxxxxxxxx>
Change-Id: Ie3c22685d5175ad2f00988a3347935f4e8cb9cff
---
M headers/os/kernel/OS.h
M headers/private/kernel/thread_types.h
M src/bin/Jamfile
A src/bin/iotop.c
M src/system/kernel/fs/fd.cpp
M src/system/kernel/team.cpp
6 files changed, 848 insertions(+), 2 deletions(-)
git pull ssh://git.haiku-os.org:22/haiku refs/changes/34/3634/1
diff --git a/headers/os/kernel/OS.h b/headers/os/kernel/OS.h
index c417842..cf8e9de 100644
--- a/headers/os/kernel/OS.h
+++ b/headers/os/kernel/OS.h
@@ -247,6 +247,10 @@
char args[64];
uid_t uid;
gid_t gid;
+ int64 read_sys_calls;
+ int64 write_sys_calls;
+ int64 read_bytes;
+ int64 write_bytes;
} team_info;
#define B_CURRENT_TEAM 0
diff --git a/headers/private/kernel/thread_types.h
b/headers/private/kernel/thread_types.h
index 926baaf..53e9f10 100644
--- a/headers/private/kernel/thread_types.h
+++ b/headers/private/kernel/thread_types.h
@@ -200,6 +200,30 @@
namespace BKernel {
+struct io_accounting {
+ vint64 read_sys_calls;
+ vint64 write_sys_calls;
+
+ vint64 write;
+ vint64 read;
+
+public:
+ vint64 get_read_syscalls(void) { return
atomic_get64((int64*)&read_sys_calls); }
+
+ vint64 get_write_syscalls(void) { return
atomic_get64((int64*)&write_sys_calls); }
+
+ vint64 get_wrote_bytes(void) { return atomic_get64((int64*)&write);
}
+
+ vint64 get_read_bytes(void) { return atomic_get64((int64*)&read);
}
+
+ void read_syscall(void) { atomic_add64((int64*)&read_sys_calls,
1); }
+
+ void write_syscall(void) {
atomic_add64((int64*)&write_sys_calls, 1); }
+
+ void read_bytes(ssize_t bytes) { atomic_add64((int64*)&read, bytes); }
+
+ void write_bytes(ssize_t bytes) { atomic_add64((int64*)&write, bytes); }
+};
template<typename IDType>
struct TeamThreadIteratorEntry
@@ -290,6 +314,8 @@
gid_t* supplementary_groups;
int supplementary_group_count;
+ struct io_accounting io_acc;
+
// Exit status information. Set when the first terminal event occurs,
// immutable afterwards. Protected by fLock.
struct {
diff --git a/src/bin/Jamfile b/src/bin/Jamfile
index 3bf2496..3d6bd1e 100644
--- a/src/bin/Jamfile
+++ b/src/bin/Jamfile
@@ -74,6 +74,7 @@
StdBinCommands
watch.c
+ iotop.c
: [ BuildFeatureAttribute ncurses : library ] : $(haiku-utils_rsrc) ;
# standard commands that need libbe.so
diff --git a/src/bin/iotop.c b/src/bin/iotop.c
new file mode 100644
index 0000000..6613446
--- /dev/null
+++ b/src/bin/iotop.c
@@ -0,0 +1,761 @@
+/*
+ * Copyright 2012 Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ * Prasad Joshi <prasadjoshi.linux@xxxxxxxxx>
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <termcap.h>
+#include <termios.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <errno.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <OS.h>
+
+#define ALL "all"
+
+typedef struct {
+ team_id tid;
+ uid_t uid;
+ int64 read;
+ int64 wrote;
+ double percent;
+ char cmd[64];
+} team_ios_t;
+
+typedef struct {
+ int nthreads;
+ team_ios_t *threads;
+} team_ios_list_t;
+
+typedef enum {
+ TID = 0,
+ UID,
+ READ,
+ WRITE,
+ PERCENT,
+ CMD
+} SORT_KEY;
+
+static char *sort_keys[] = {
+ "Proccesses ID",
+ "User ID",
+ "Read Bandwidth",
+ "Write Bandwidth",
+ "Percentage of total IOs",
+ "Process Name",
+};
+
+static int rows; /* # rows on the screen */
+static int cols; /* # columns on the screen */
+static char *clear_screen = NULL;
+static bool screen_size_changed = false; /* set in signal handler */
+static SORT_KEY sort_key = PERCENT; /* default key for sorting data */
+static bool reverse = false; /* reverse sorting */
+static tcflag_t tty_local_modes = 0; /* saved terminal mode */
+static char *program = NULL;
+
+/* program parameters */
+static int delay = 3;
+static int iter = 0;
+
+static char *user = "all";
+static uid_t user_uid = 0;
+static bool user_filter = false;
+
+static char *proc = "all";
+static team_id *tids = NULL;
+
+static bool only_ios = false;
+
+static void usage(void)
+{
+ printf( "Usage: %s\n"
+ "-d <delay in seconds (default = 3)>\n"
+ "-i <# iterations (default = 0)>\n"
+ "-u <monitor processes of user (default = all)>\n"
+ "-p <comma separated list of pids to monitor (default = all)>\n"
+ "-o only show processes doing ios (default = false)\n"
+ "-h show this message\n", program);
+}
+
+static void end(const char *msg, int rc)
+{
+ if (msg)
+ fprintf(stderr, "%s: %s", msg, strerror(rc));
+
+ if (strcmp(user, ALL))
+ free(user);
+
+ if (strcmp(proc, ALL))
+ free(proc);
+
+ exit(rc);
+}
+
+/*
+ * Converts uid to user name.
+ * Caller is supposed to free the memory allocated for user name.
+ */
+static char *user_name(uid_t uid)
+{
+ struct passwd *b;
+
+ b = getpwuid(uid);
+ if (!b)
+ return NULL;
+ return strdup(b->pw_name);
+}
+
+/*
+ * Convert user id to user name
+ */
+static int user_id(const char *name, uid_t *uid)
+{
+ struct passwd *b;
+
+ b = getpwnam(name);
+ if (!b)
+ return -1;
+ *uid = b->pw_uid;
+ return 0;
+}
+
+static bool match_tid(team_id tid, team_id *tids)
+{
+ team_id *t;
+
+ t = tids;
+ while (*t) {
+ if (*t == tid)
+ return true;
+ t++;
+ }
+ return false;
+}
+
+static void xtract_team_list(char *proc)
+{
+ char *s;
+ int count;
+ int no_tids;
+ char *x;
+ char *s1;
+ int i;
+ bool done = false;
+ team_id tid;
+
+ s = proc;
+ count = 0;
+ while (s) {
+ s = strchr(s, ',');
+ count++;
+ if (!s)
+ break;
+ s++;
+ }
+
+ /*
+ * Since the list of tids is delimted with 0 tid, we need to allocate
+ * memory for an additional tid. For example if user input is 1,2,3,4
+ * then count will be 3 and memory for 5 tids will be allocated.
+ */
+ no_tids = count + 2;
+
+ tids = calloc(no_tids, sizeof(team_id));
+ if (!tids) {
+ fprintf(stderr, "Memory Allocation Failed.\n");
+ end(__func__, ENOMEM);
+ }
+
+ x = s1 = s = strdup(proc);
+ i = 0;
+ while (!done) {
+ s1 = strchr(s, ',');
+
+ if (!s1)
+ done = true;
+ else
+ *s1 = 0;
+
+ tid = atol(s);
+ if (tid) {
+ tids[i] = tid;
+ i++;
+ }
+
+ s = s1 + 1;
+ }
+ tids[i] = 0;
+ free(x);
+}
+
+static int parse_arguments(int argc, char *argv[])
+{
+ int opt;
+ bool invalid = false;
+
+ while ((opt = getopt(argc, argv, "d:i:u:p:oh")) != -1) {
+ switch (opt) {
+ case 'd':
+ delay = atoi(optarg);
+ if (!delay || delay < 0) {
+ fprintf(stderr, "Invalid argument to -- d\n");
+ invalid = true;
+ }
+ break;
+ case 'i':
+ iter = atoi(optarg);
+ if (!iter || iter < 0) {
+ fprintf(stderr, "Invalid argument to -- i\n");
+ invalid = true;
+ }
+ break;
+ case 'u': {
+ char *u = strdup(optarg);
+ if (strcmp(u, "all")) {
+ int rc = user_id(u, &user_uid);
+ if (rc < 0) {
+ fprintf(stderr, "No such user '%s'\n",
u);
+ free(u);
+ invalid = true;
+ }
+ user = u;
+ user_filter = true;
+ } else {
+ /* TODO: Handle user with name all */
+ free(u);
+ }
+ break;
+ }
+ case 'p':
+ proc = strdup(optarg);
+ break;
+ case 'o':
+ only_ios = true;
+ break;
+ case 'h':
+ usage();
+ end(NULL, 0);
+ default:
+ usage();
+ end(NULL, EINVAL);
+ }
+ }
+
+ if (invalid) {
+ usage();
+ end(NULL, EINVAL);
+ }
+
+ if (!strcmp(proc, "all"))
+ return 0;
+
+ /* proc must be comma separated list of pids */
+ xtract_team_list(proc);
+
+ return 0;
+}
+
+static void window_changed(int unused)
+{
+ screen_size_changed = true;
+}
+
+static void clear(void)
+{
+ if (clear_screen) {
+ printf(clear_screen);
+ fflush(stdout);
+ }
+}
+
+static void cleanup(void)
+{
+ struct termios tty;
+
+ free(clear_screen);
+
+ /* restore the terminal setting */
+ tcgetattr(STDIN_FILENO, &tty);
+ tty.c_lflag = tty_local_modes;
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &tty);
+}
+
+static int setup_term(bool only_rows, bool set_tty)
+{
+ struct termios tty;
+ struct winsize ws;
+ char *term;
+ char *str;
+ char buf[2048];
+ char *entries;
+
+ if (set_tty) {
+ errno = 0;
+ if (tcgetattr(STDIN_FILENO, &tty) < 0)
+ return -errno;
+
+ tty_local_modes = tty.c_lflag;
+ tty.c_lflag &= ~(ECHO | ICANON);
+
+ errno = 0;
+ if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tty) < 0)
+ return -errno;
+ }
+
+ if (ioctl(1, TIOCGWINSZ, &ws) < 0)
+ return 0;
+
+ if (ws.ws_row <= 0)
+ return 0;
+ rows = ws.ws_row;
+
+ if (ws.ws_col <= 0)
+ return 0;
+ cols = ws.ws_col;
+
+ if (only_rows)
+ return 1;
+
+ term = getenv("TERM");
+ if (term == NULL)
+ return 0;
+
+ if (tgetent(buf, term) <= 0)
+ return 0;
+
+ entries = &buf[0];
+ str = tgetstr("cl", &entries);
+ if (str == NULL)
+ return 0;
+
+ clear_screen = strdup(str);
+ return 1;
+}
+
+/*
+ * Convert bytes into more user readable form of KB, MB, or GB
+ */
+static inline void bandwidth(char *buf, int size, int64 bytes)
+{
+ double bw = bytes;
+ double bw1 = 0;
+ int i;
+ char unit[] = { 'B', 'K', 'M', 'G', 'T' };
+
+ i = 0;
+ while ((int) bw) {
+ bw1 = bw;
+ bw /= 1024;
+ i++;
+ }
+
+ if (!i)
+ i++;
+
+ snprintf(buf, size, "%0.2f %c/s", bw1, unit[i - 1]);
+ return;
+}
+
+/*
+ * Display a line on terminal, limit to available characters in column
+ */
+static int display_line(const char *f, ...)
+{
+ va_list ap;
+ char line[cols];
+ int n;
+
+ va_start(ap, f);
+ /* sizeof(line) - 1 since we need to add a trailing newline */
+ n = vsnprintf(line, sizeof(line) - 1, f, ap);
+ va_end(ap);
+
+ if (n < 0)
+ return -1;
+
+ printf("%s\n", line);
+ return 0;
+}
+
+static void char_repeat(char *buf, char ch, int count)
+{
+ buf[count--] = 0;
+ for (; count >= 0; count--)
+ buf[count] = ch;
+}
+
+static void display_preferences(void)
+{
+ char buf[cols];
+ char_repeat(buf, '-', cols - 1);
+ display_line("%s", buf); // Line 1
+
+ display_line("User: %s", user); // Line 2
+ display_line("Processes: %s", proc); // Line 3
+ if (only_ios)
+ display_line("Only showing processes doing IOs."); // Line 4
+
+ display_line("Sorted according to '%s'.\tReverse Sorting: %s",
+ sort_keys[sort_key], reverse ? "true" : "false");//
Line 5
+ display_line("Refreshing every %d seconds.", delay); // Line 6
+ if (iter)
+ display_line("Iterations still remaining: %d.", iter);
+}
+
+static void display_delta(team_ios_t *d, int teams, int64 total_reads,
+ int64 total_writes)
+{
+ char rbw[256];
+ char wbw[256];
+ team_ios_t *t;
+ int i;
+ char *n;
+
+ clear();
+
+ bandwidth(rbw, sizeof(rbw), total_reads);
+ bandwidth(wbw, sizeof(wbw), total_writes);
+
+ display_line("Total Disk Reads: %11s | Total Disk Writes: %11s", rbw,
+ wbw);
+ display_line("\n%7s %8s %11s %11s %9s %s", "TID", "USER",
+ "READ BW", "WRITE BW", "IO %", "Command");
+
+ t = d;
+ for (i = 0; i < teams; i++, t++) {
+ if (i + 8 > rows) {
+ /*
+ * maximum rows can only be disaplyed on terminal.
+ * Additional 8 rows are left for displaying user
+ * preferences and title.
+ */
+ continue;
+ }
+
+ if (only_ios && (!(t->read + t->wrote))) {
+ /* skip: user has asked for processes doing IOs */
+ continue;
+ }
+
+ if (user_filter && (user_uid != t->uid)) {
+ /* skip: looking for processes of a selected user */
+ continue;
+ }
+
+ if (tids) {
+ /* must be the last condition for better performance */
+ if (!match_tid(t->tid, tids)) {
+ /* skip: looking for processes with specific
tids */
+ continue;
+ }
+ }
+
+ n = user_name(t->uid);
+ bandwidth(rbw, sizeof(rbw), t->read);
+ bandwidth(wbw, sizeof(wbw), t->wrote);
+
+
+ display_line("%7d %8s %11s %11s %7.2f %% %s", t->tid, n,
+ rbw, wbw, t->percent, t->cmd);
+
+ free(n);
+ }
+
+ display_preferences();
+}
+
+static int compare_ios(const void *a, const void *b)
+{
+ const team_ios_t *d1 = a;
+ const team_ios_t *d2 = b;
+ int rc;
+
+ switch (sort_key) {
+ case TID:
+ rc = d1->tid - d2->tid;
+ break;
+ case UID:
+ rc = d2->uid - d1->uid;
+ break;
+ case READ:
+ rc = d2->read - d1->read;
+ break;
+ case WRITE:
+ rc = d2->wrote - d1->wrote;
+ break;
+ case PERCENT:
+ rc = d2->percent - d1->percent;
+ break;
+ case CMD:
+ rc = strcmp(d1->cmd, d2->cmd);
+ break;
+ default:
+ end("compare_ios", 1);
+ }
+
+ if (!rc) {
+ /* use ios performed for deciding order */
+ rc = (d2->read + d2->wrote) - (d1->read + d1->wrote);
+ }
+
+ return reverse? 0 - rc : rc;
+}
+
+static void cal_io_percent(team_ios_t *d, int teams, int64 total_ios)
+{
+ team_ios_t *t;
+ int i;
+
+ t = d;
+ for (i = 0; i < teams; i++, t++)
+ t->percent = (100 * (t->wrote + t->read)) / (double) total_ios;
+}
+
+static int grow(team_ios_list_t *l)
+{
+ l->nthreads++;
+ l->threads = realloc(l->threads, sizeof(*l->threads) * l->nthreads);
+
+ if (!l->threads)
+ return -1;
+ return 0;
+}
+
+static team_ios_list_t *gather(team_ios_list_t *old)
+{
+ team_ios_list_t *l;
+ int32 c = 0; // cookie
+ team_info tm;
+ int no;
+ team_ios_t *t;
+ team_ios_t *delta;
+ int i;
+ team_ios_t *ot;
+ team_ios_t *dt;
+ int64 total_reads = 0;
+ int64 total_writes = 0;
+
+ l = malloc(sizeof(*l));
+ if (!l) {
+ fprintf(stderr, "Memory allocation failed.\n");
+ return NULL;
+ }
+ memset(l, 0, sizeof(*l));
+
+ while (get_next_team_info(&c, &tm) == B_NO_ERROR) {
+ if (grow(l) < 0) {
+ fprintf(stderr, "Memory allocation failed.\n");
+ return NULL;
+ }
+
+ no = l->nthreads - 1;
+ t = l->threads + no;
+
+ t->tid = tm.team;
+ t->uid = tm.uid;
+ t->read = tm.read_bytes;
+ t->wrote = tm.write_bytes;
+ strlcpy(t->cmd, tm.args, sizeof(t->cmd));
+ }
+
+ delta = malloc(sizeof(*delta) * (l->nthreads));
+ if (!delta) {
+ fprintf(stderr, "Memory allocation failed.\n");
+ return NULL;
+ }
+
+ for (i = 0; i < l->nthreads; i++) {
+ t = l->threads + i;
+
+ bool new_process = true;
+
+ if (old) {
+ /* find team in old list */
+ int j;
+ for (j = 0; j < old->nthreads; j++) {
+ ot = old->threads + j;
+
+ if (ot->tid == t->tid) {
+ /* process was already running */
+ new_process = false;
+ break;
+ }
+ }
+ }
+
+ dt = delta + i;
+ if (new_process) {
+ /* a newly process has been started */
+ dt->read = t->read;
+ dt->wrote = t->wrote;
+ } else {
+ dt->read = t->read - ot->read;
+ dt->wrote = t->wrote - ot->wrote;
+ }
+
+ dt->tid = t->tid;
+ dt->uid = t->uid;
+ total_reads += dt->read;
+ total_writes += dt->wrote;
+ strlcpy(dt->cmd, t->cmd, sizeof(dt->cmd));
+ }
+
+ if (old) {
+ /* calculate percentage of total IOs for each team */
+ cal_io_percent(delta, l->nthreads, total_reads + total_writes);
+
+ /* sort teams */
+ qsort(delta, l->nthreads, sizeof(*delta), compare_ios);
+
+ /* display teams */
+ display_delta(delta, l->nthreads, total_reads, total_writes);
+
+ free(delta);
+
+ /* ols list of teams is no longer needed */
+ free(old->threads);
+ free(old);
+ }
+ return l;
+}
+
+static void handle_key(int key)
+{
+ switch (key) {
+ case 't':
+ sort_key = TID;
+ break;
+ case 'u':
+ sort_key = UID;
+ break;
+ case 'r':
+ sort_key = READ;
+ break;
+ case 'w':
+ sort_key = WRITE;
+ break;
+ case 'p':
+ sort_key = PERCENT;
+ break;
+ case 'c':
+ sort_key = CMD;
+ break;
+ case 'x':
+ /* toggle the reverse sorting */
+ reverse = !reverse;
+ break;
+ case 'q':
+ /* gracefully end the program */
+ end(NULL, 0);
+ }
+}
+
+static int user_input(void)
+{
+ long file_flags;
+ int rc;
+ char c;
+
+ file_flags = fcntl(STDIN_FILENO, F_GETFL);
+ if (file_flags < 0)
+ file_flags = 0;
+
+ if (fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK | file_flags) < 0)
+ end("fcntl", errno);
+
+ rc = read(STDIN_FILENO, &c, 1);
+
+ if (fcntl(STDIN_FILENO, F_SETFL, file_flags) < 0)
+ end("fcntl", errno);
+
+ if (rc < 0) {
+ /* no user input */
+ return -1;
+ }
+
+ /* user has pressed a key */
+ return c;
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ team_ios_list_t *base_line = NULL;
+ bool iter_flag;
+
+ program = argv[0];
+ parse_arguments(argc, argv);
+
+ rc = setup_term(false, true);
+ if (rc < 0)
+ end("setup_term", -rc);
+
+ signal(SIGWINCH, window_changed);
+ atexit(cleanup);
+
+ base_line = gather(NULL);
+ /*
+ * We should not be displaying zero IOs during first iteration, wait
+ * for a second so that we will have something to display.
+ */
+ sleep(1);
+
+ iter_flag = !!iter;
+ while (!iter_flag || iter--) {
+ if (screen_size_changed) {
+ setup_term(true, false);
+ screen_size_changed = false;
+ }
+
+ base_line = gather(base_line);
+
+ rc = user_input();
+ if (rc <= 0) {
+ /* no user input, delay the execution */
+ fd_set fs;
+ struct timeval tv = {delay, 0};
+
+ FD_ZERO(&fs);
+ FD_SET(STDIN_FILENO, &fs);
+
+ /* delay until user input or timeout */
+ rc = select(1, &fs, NULL, NULL, &tv);
+ if (rc < 0) {
+ /*
+ * we might have been woken-up because of screen
+ * size changed signal. If it was the case then
+ * screen must be redrawn immediately.
+ */
+ rc = 0;
+ if (errno != EINTR)
+ end("select", errno);
+ }
+
+ if (rc) {
+ /* input from user is available */
+ rc = user_input();
+ if (rc < 0)
+ end("read", 1);
+ if (rc == 0)
+ end(NULL, 0);
+ }
+ }
+
+ if (rc > 0) {
+ /* user has pressed a key */
+ handle_key(rc);
+ }
+ }
+ return 0;
+}
diff --git a/src/system/kernel/fs/fd.cpp b/src/system/kernel/fs/fd.cpp
index 4389bfe..13aea53 100644
--- a/src/system/kernel/fs/fd.cpp
+++ b/src/system/kernel/fs/fd.cpp
@@ -769,15 +769,36 @@
else
status = descriptor->ops->fd_read(descriptor, pos, buffer,
&length);
+ Thread *thread = thread_get_current_thread();
+ Team* team = thread->team;
+ TeamLocker teamLocker(team);
+ struct BKernel::io_accounting *acc;
+
+ acc = &team->io_acc;
+
+ /* account of for system call */
+ if (write)
+ acc->write_syscall();
+ else
+ acc->read_syscall();
+
if (status != B_OK)
return status;
+ ssize_t rc = length <= SSIZE_MAX ? (ssize_t)length : SSIZE_MAX;
+
+ /* account for IO bytes */
+ if (write)
+ acc->write_bytes(rc);
+ else
+ acc->read_bytes(rc);
+
if (movePosition) {
descriptor->pos = write && (descriptor->open_mode & O_APPEND)
!= 0
? descriptor->ops->fd_seek(descriptor, 0, SEEK_END) :
pos + length;
}
- return length <= SSIZE_MAX ? (ssize_t)length : SSIZE_MAX;
+ return rc;
}
@@ -848,7 +869,7 @@
if (status != B_OK) {
if (bytesTransferred == 0)
- return status;
+ goto error;
status = B_OK;
break;
}
@@ -869,6 +890,29 @@
? descriptor->ops->fd_seek(descriptor, 0, SEEK_END) :
pos;
}
+error:
+ Thread *thread = thread_get_current_thread();
+ Team* team = thread->team;
+ TeamLocker teamLocker(team);
+ struct BKernel::io_accounting *acc;
+
+ acc = &team->io_acc;
+
+ /* account of for system call */
+ if (write)
+ acc->write_syscall();
+ else
+ acc->read_syscall();
+
+ if (status != B_OK)
+ return status;
+
+ /* account for IO bytes */
+ if (write)
+ acc->write_bytes(bytesTransferred);
+ else
+ acc->read_bytes(bytesTransferred);
+
return bytesTransferred;
}
diff --git a/src/system/kernel/team.cpp b/src/system/kernel/team.cpp
index 51421eb..d8ab709 100644
--- a/src/system/kernel/team.cpp
+++ b/src/system/kernel/team.cpp
@@ -507,6 +507,9 @@
fUserDefinedTimerCount = 0;
fCoreDumpCondition = NULL;
+
+ // initialize all io accounting counters to 0
+ memset(&io_acc, 0, sizeof(io_acc));
}
@@ -2685,6 +2688,13 @@
info->uid = team->effective_uid;
info->gid = team->effective_gid;
+ struct BKernel::io_accounting *acc = &team->io_acc;
+
+ info->read_sys_calls = acc->get_read_syscalls();
+ info->write_sys_calls = acc->get_write_syscalls();
+ info->read_bytes = acc->get_read_bytes();
+ info->write_bytes = acc->get_wrote_bytes();
+
strlcpy(info->args, team->Args(), sizeof(info->args));
info->argc = 1;
--
To view, visit https://review.haiku-os.org/c/haiku/+/3634
To unsubscribe, or for help writing mail filters, visit
https://review.haiku-os.org/settings
Gerrit-Project: haiku
Gerrit-Branch: master
Gerrit-Change-Id: Ie3c22685d5175ad2f00988a3347935f4e8cb9cff
Gerrit-Change-Number: 3634
Gerrit-PatchSet: 1
Gerrit-Owner: X512 <danger_mail@xxxxxxx>
Gerrit-MessageType: newchange