diff --git a/Makefile b/Makefile
index 40f307a..1d5278b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
CC = gcc
CFLAGS = -g -Wall -Werror -fPIC -std=gnu99
-DEPS = resource.h resource_impl.h resmem.h resnet.h resproc.h resvm.h rescpu.h resfs.h
-OBJ = resource.o resmem.o resnet.o resproc.o reskern.o resvm.o rescpu.o resfs.o net_if.o net_route.o net_arp.o
+DEPS = resource.h resource_impl.h resmem.h resnet.h resproc.h resvm.h rescpu.h resfs.h stat.h
+OBJ = resource.o resmem.o resnet.o resproc.o reskern.o resvm.o rescpu.o resfs.o net_if.o net_route.o net_arp.o stat.o
TEST = test
RM = rm -rf
CP = cp
diff --git a/resource.c b/resource.c
index 6762a47..a3f22fe 100644
--- a/resource.c
+++ b/resource.c
@@ -31,6 +31,7 @@
#include "resnet.h"
#include "resproc.h"
#include "resvm.h"
+#include "stat.h"
#include "rescpu.h"
#include "resfs.h"
@@ -212,6 +213,9 @@ int res_read(int res_id, void *out, size_t out_sz, void **hint, int pid, int fla
if (res_id >= DEV_MIN && res_id < DEV_MAX)
return getdevinfo(res_id, out, out_sz, hint, flags);
+ if (res_id >= STAT_MIN && res_id < STAT_MAX)
+ return getstatinfo(res_id, out, out_sz, hint, flags);
+
if (res_id >= FS_MIN && res_id < FS_MAX)
return getfsinfo(res_id, out, out_sz, hint, flags);
diff --git a/resource.h b/resource.h
index ecd6aa0..9d5304d 100644
--- a/resource.h
+++ b/resource.h
@@ -157,6 +157,10 @@ typedef struct res_blk {
#define RES_CPU_CORECOUNT 6002
#define CPU_MAX 6010
+#define STAT_MIN 7000
+#define RES_STAT_INFO 7001
+#define STAT_MAX 7002
+
#define FS_MIN 8000
#define FS_AIONR 8001
#define FS_AIOMAXNR 8002
@@ -549,6 +553,32 @@ struct vmstat {
unsigned long nr_unstable;
};
+struct cpu_stat {
+ unsigned long long user;
+ unsigned long long nice;
+ unsigned long long system;
+ unsigned long long idle;
+ unsigned long long iowait;
+ unsigned long long irq;
+ unsigned long long softirq;
+ unsigned long long steal;
+ unsigned long long guest;
+ unsigned long long guest_nice;
+};
+
+struct stat_info {
+ struct cpu_stat cpu;
+ struct cpu_stat *all_cpu; /* Array of len cpu_num */
+ int cpu_num;
+ char intr[9000]; // total of all interrupts serviced(since boot)
+ unsigned long long ctxt;
+ unsigned long long btime;
+ unsigned long long processes;
+ unsigned long long procs_running;
+ unsigned long long procs_blocked;
+ char softirq[9000]; /* Number of softirq for all CPUs. */
+};
+
/* Allocating memory and building a res_blk structure to return bulk
* resource information.
*/
diff --git a/stat.c b/stat.c
new file mode 100644
index 0000000..831cfeb
--- /dev/null
+++ b/stat.c
@@ -0,0 +1,164 @@
+/* Copyright (C) 2023, Oracle and/or its affiliates. All rights reserved
+ *
+ * This file is part of libresource.
+ *
+ * libresource is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libresource 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libresource. If not, see .
+ */
+
+#ifndef _RESOURCE_H
+#include "resource.h"
+#endif
+#include
+#include
+#include
+#include
+#include "resvm.h"
+#include "resource_impl.h"
+#include
+#include
+#include "stat.h"
+
+static char buffer[20000];
+
+static int populate_statcpu(struct cpu_stat *all_cpu, int cpu_num)
+{
+ char buf[36];
+ const char *cstr;
+
+ if (!all_cpu) {
+ return -1;
+ }
+ for (int i = 0; i < cpu_num; i++) {
+ snprintf(buf, 36, "cpu%d", i);
+ cstr = strstr(buffer, buf);
+ if (cstr) {
+ cstr += strlen(buf)+1;
+ sscanf(cstr, "%Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu",
+ &all_cpu->user,
+ &all_cpu->nice,
+ &all_cpu->system,
+ &all_cpu->idle,
+ &all_cpu->iowait,
+ &all_cpu->irq,
+ &all_cpu->softirq,
+ &all_cpu->steal,
+ &all_cpu->guest,
+ &all_cpu->guest_nice);
+ }
+ all_cpu++;
+ }
+ return 0;
+}
+
+static int populate_statinfo(void *out, int test)
+{
+ char *cstr;
+ struct stat_info *st;
+ int cpu_num;
+
+ st = (struct stat_info *) out;
+ cstr = strstr(buffer, "cpu ");
+ if (cstr) {
+ sscanf(cstr, "cpu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu",
+ &st->cpu.user,
+ &st->cpu.nice,
+ &st->cpu.system,
+ &st->cpu.idle,
+ &st->cpu.iowait,
+ &st->cpu.irq,
+ &st->cpu.softirq,
+ &st->cpu.steal,
+ &st->cpu.guest,
+ &st->cpu.guest_nice);
+ }
+ cstr = strstr(buffer, "intr ");
+ memset(&st->intr, '\0', sizeof(st->intr));
+ if (cstr) {
+ unsigned int bytes = 0;
+ char *cstr1 = cstr + 5;
+ while (*cstr1 != '\n' && bytes < 8999) {
+ cstr1++;
+ bytes++;
+ }
+ strncpy(st->intr, cstr+5, bytes);
+ }
+ cstr = strstr(buffer, "ctxt ");
+ if (cstr)
+ sscanf(cstr, "ctxt %Lu", &st->ctxt);
+ cstr = strstr(buffer, "btime ");
+ if (cstr)
+ sscanf(cstr, "btime %Lu", &st->btime);
+ cstr = strstr(buffer, "processes ");
+ if (cstr)
+ sscanf(cstr, "processes %Lu", &st->processes);
+ cstr = strstr(buffer, "procs_running ");
+ if (cstr)
+ sscanf(cstr, "procs_running %Lu", &st->procs_running);
+ cstr = strstr(buffer, "procs_blocked ");
+ if (cstr)
+ sscanf(cstr, "procs_blocked %Lu", &st->procs_blocked);
+ cstr = strstr(buffer, "softirq ");
+ memset(&st->softirq, '\0', sizeof(st->softirq));
+ if (cstr) {
+ unsigned int bytes = 0;
+ char *cstr1 = cstr + 8;
+ while (*cstr1 != '\n' && bytes < 8999) {
+ cstr1++;
+ bytes++;
+ }
+ strncpy(st->softirq, cstr+8, bytes);
+ }
+
+ cpu_num = sysconf(_SC_NPROCESSORS_ONLN);
+ populate_statcpu(st->all_cpu, cpu_num);
+ return 0;
+}
+
+int getstatexist(int res_id, void *exist, size_t sz, void *hint, int flags)
+{
+ int ret;
+ ret = file_to_buf("./stat_info.orig", buffer, sizeof(buffer));
+ if (ret == -1)
+ return -1;
+ ret = populate_statinfo(exist, 1);
+ return ret;
+}
+
+int getstatinfo(int res_id, void *out, size_t sz, void **hint, int flags)
+{
+ int ret, cpu_num, cpu_size;
+
+#ifdef TESTING
+ ret = file_to_buf("./stat_info.orig", buffer, sizeof(buffer));
+#else
+ ret = file_to_buf(STAT_FILE, buffer, sizeof(buffer));
+#endif
+ if (ret == -1)
+ return -1;
+
+ switch (res_id) {
+ case RES_STAT_INFO:
+ cpu_num = sysconf(_SC_NPROCESSORS_ONLN);
+ cpu_size = sizeof(struct cpu_stat) * cpu_num;
+ CHECK_SIZE(sz, (sizeof(struct stat_info) + cpu_size));
+ ret = populate_statinfo(out, 0);
+ break;
+ default:
+ eprintf("Resource Id is invalid");
+ errno = EINVAL;
+ return -1;
+
+ }
+ return ret;
+}
diff --git a/stat.h b/stat.h
new file mode 100644
index 0000000..471f9e9
--- /dev/null
+++ b/stat.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 2023, Oracle and/or its affiliates. All rights reserved
+ *
+ * This file is part of libresource.
+ *
+ * libresource is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libresource 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libresource. If not, see .
+ */
+
+#ifndef _STAT_H
+#define _STAT_H
+
+#define STAT_FILE "/proc/stat"
+
+extern int getstatinfo(int res_id, void *out, size_t sz, void **hint,
+ int flags);
+#endif /* _STAT_H */
diff --git a/tests/MEM/mem_test.c b/tests/MEM/mem_test.c
index 718f19b..536b6e5 100644
--- a/tests/MEM/mem_test.c
+++ b/tests/MEM/mem_test.c
@@ -40,7 +40,10 @@ int main(int argc, char **argv)
exit(1);
}
fp = fopen ("./mem_info.txt", "w");
-
+ if (fp == NULL) {
+ printf("mem_info.txt does not exist!\n");
+ exit(1);
+ }
if (exist.memtotal)
fprintf(fp, "MemTotal: %lu kB\n", mem.memtotal);
if (exist.memfree)
diff --git a/tests/STAT/stat.sh b/tests/STAT/stat.sh
new file mode 100755
index 0000000..efb2f3a
--- /dev/null
+++ b/tests/STAT/stat.sh
@@ -0,0 +1,10 @@
+export LD_LIBRARY_PATH=`git rev-parse --show-toplevel`
+cd $LD_LIBRARY_PATH
+cd tests/STAT
+rm -f stat_info.orig
+rm -f stat_info.txt
+cc -I $LD_LIBRARY_PATH -std=gnu99 -o stat_test stat_test.c -L $LD_LIBRARY_PATH -lresource
+cat /proc/stat > stat_info.orig
+./stat_test
+diff stat_info.orig stat_info.txt
+
diff --git a/tests/STAT/stat_test.c b/tests/STAT/stat_test.c
new file mode 100644
index 0000000..cc54b05
--- /dev/null
+++ b/tests/STAT/stat_test.c
@@ -0,0 +1,81 @@
+/* Copyright (C) 2023, Oracle and/or its affiliates. All rights reserved
+ *
+ * This file is part of libresource.
+ *
+ * libresource is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libresource 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libresource. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+int main(int argc, char **argv)
+{
+ struct stat_info stats, *st;
+ int cpu_num, size, err = 0;
+ FILE *fp;
+ char buf[36];
+ struct cpu_stat *all_cpu;
+
+ cpu_num = sysconf(_SC_NPROCESSORS_ONLN);
+ size = sizeof(struct cpu_stat) * cpu_num;
+ stats.all_cpu = (struct cpu_stat *) malloc(size);
+ err = res_read(RES_STAT_INFO, &stats, sizeof(stats)+size, NULL, 0, 0);
+ if (err != 0)
+ printf("err is %d\n",err);
+ st = &stats;
+ fp = fopen ("./stat_info.txt", "w");
+ if (fp == NULL) {
+ printf("stat_info.txt does not exist!\n");
+ exit(1);
+ }
+ fprintf(fp, "cpu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu\n",
+ st->cpu.user,
+ st->cpu.nice,
+ st->cpu.system,
+ st->cpu.idle,
+ st->cpu.iowait,
+ st->cpu.irq,
+ st->cpu.softirq,
+ st->cpu.steal,
+ st->cpu.guest,
+ st->cpu.guest_nice);
+ all_cpu = st->all_cpu;
+ for (int i = 0; i < cpu_num; i++) {
+ sprintf(buf, "cpu%d", i);
+ fprintf(fp, "%s %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu\n",
+ buf,
+ all_cpu->user,
+ all_cpu->nice,
+ all_cpu->system,
+ all_cpu->idle,
+ all_cpu->iowait,
+ all_cpu->irq,
+ all_cpu->softirq,
+ all_cpu->steal,
+ all_cpu->guest,
+ all_cpu->guest_nice);
+ all_cpu++;
+ }
+ fprintf(fp, "intr %s\n", st->intr);
+ fprintf(fp, "ctxt %Lu\n",st->ctxt);
+ fprintf(fp, "btime %Lu\n", st->btime);
+ fprintf(fp, "processes %Lu\n", st->processes);
+ fprintf(fp, "procs_running %Lu\n", st->procs_running);
+ fprintf(fp, "procs_blocked %Lu\n", st->procs_blocked);
+ fprintf(fp, "softirq %s\n", st->softirq);
+ fclose(fp);
+}