Files
system-monitor/myMonitoringTool.c
2026-08-10 22:27:53 -04:00

254 lines
6.0 KiB
C

#include "myMonitoringTool.h"
#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#define MAIN 0
#define MEM 1
#define CPU 2
#define CORE 3
bool isint(char *str) {
///_|> descry: checks if a string is an integer
///_|> str: string to check
///_|> returning: true iff is an integer
int i = 0;
while (str[i] != '\0') {
if (!isdigit(str[i])) {
return false;
}
i += 1;
}
return true;
}
void sigint_handler(int sig) {
///_|> descry: Handles SIGINT, exiting if pressed twice
///_|> sig: signal number
///_|> returning: void
static int count = 0;
if (count == 0) {
printf("\nPress Ctrl+C again to quit");
count++;
char buf[LINE_BUF];
fgets(buf, sizeof buf, stdin);
count = 0;
if (signal(SIGINT, sigint_handler) != 0) {
perror("signal");
exit(1);
}
} else {
exit(0);
}
}
// Parse input, read values, display requested output
int main(int argc, char **argv) {
///_|> Parse CLAs, implement children to read data, prints childrens data
///_|> argc: number of arguments including function name
///_|> argv: list of string arguments
///_|> retuning: integer success code
if (signal(SIGTSTP, SIG_IGN) != 0) {
perror("signal");
exit(1);
}
bool show_mem = false;
bool show_cpu = false;
bool show_cores = false;
int samples = 20;
int tdelay = 5e5;
int nums_given = 0;
// Parse input
for (int i = 1; i < argc; i++) {
char first9[10];
strncpy(first9, argv[i], 9);
first9[9] = '\0';
char first10[11];
strncpy(first10, argv[i], 10);
first10[10] = '\0';
if (strcmp(argv[i], "--memory") == 0) {
show_mem = true;
} else if (strcmp(argv[i], "--cpu") == 0) {
show_cpu = true;
} else if (strcmp(argv[i], "--cores") == 0) {
show_cores = true;
} else if (isint(argv[i])) {
if (nums_given == 0) {
samples = atoi(argv[i]);
} else if (nums_given == 1) {
tdelay = atoi(argv[i]);
} else {
printf("Unknown flag %s\nUsage: myMonitoringTool [samples [tdelay]] "
"[--memory] [--cpu] [--cores] [--samples=N] [--tdelay=T]\n",
argv[i]);
exit(1);
}
nums_given += 1;
} else if (strcmp(first9, "--tdelay=") == 0) {
char value[LINE_BUF];
strncpy(value, argv[i] + 9, 20);
tdelay = atoi(value);
} else if (strcmp(first10, "--samples=") == 0) {
char value[LINE_BUF];
strncpy(value, argv[i] + 10, 20);
samples = atoi(value);
} else {
printf("Unknown flag %s\nUsage: myMonitoringTool [samples [tdelay]] "
"[--memory] [--cpu] [--cores] [--samples=N] [--tdelay=T]\n",
argv[i]);
exit(1);
}
}
bool show_all = !(show_mem || show_cpu || show_cores);
if (show_cores && !(show_mem || show_cpu || show_all)) {
samples = 1;
}
int cpu_cores = get_file_line_value("/proc/cpuinfo", 11);
int p[2]; // Mem pipe
int q[2]; // Cpu pipe
int r[2]; // Core pipe
if (pipe(p) == -1 || pipe(q) == -1) {
perror("pipe");
exit(1);
}
int cpu_proc = fork();
int mem_proc = -2;
if (cpu_proc != 0) {
mem_proc = fork();
}
if (cpu_proc == -1 || mem_proc == -1) {
perror("fork");
exit(1);
}
int id = -1;
if (cpu_proc != 0 && mem_proc > 0) {
close(p[1]);
close(q[1]);
id = MAIN;
if (signal(SIGINT, sigint_handler) != 0) {
perror("signal");
exit(1);
}
} else if (cpu_proc == 0 && mem_proc <= 0) {
close(p[0]);
close(p[1]);
close(q[0]);
id = CPU;
if (signal(SIGINT, SIG_IGN) != 0) {
perror("signal");
exit(1);
}
} else {
assert(cpu_proc != 0 && mem_proc == 0);
close(p[0]);
close(q[0]);
close(q[1]);
id = MEM;
if (signal(SIGINT, SIG_IGN) != 0) {
perror("signal");
exit(1);
}
}
// Prepare the core info
char coreinfo[PANE_BUF];
if (id == MAIN && (show_cores || show_all)) {
if (pipe(r) == -1) {
perror("pipe");
exit(1);
}
int pid = fork();
if (pid == -1) {
perror("fork");
exit(1);
}
if (pid == 0) {
close(r[0]);
int cpu_max_freq = get_file_line_value(
"/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", 0);
draw_cores(cpu_cores, cpu_max_freq, r[1]);
exit(0);
} else {
close(r[1]);
}
}
// Draw the frames
int mem_total = get_file_line_value("/proc/meminfo", 0);
// Initialize arrays for values that change, scaled from 0 to 10. For use
// in children
int mem_usages[samples];
int cpu_utils[samples];
// Values that will be printed, for use in parent
char meminfo[PANE_BUF];
char cpuinfo[PANE_BUF];
// Draw, compute, and display output
for (int i = 0; i < samples; i++) {
if (id == MEM && (show_mem || show_all)) {
assert(mem_proc == 0 && cpu_proc != 0);
get_mem_usage(mem_total, meminfo, mem_usages, i);
write(p[1], meminfo, PANE_BUF);
raise(SIGSTOP);
}
if (id == CPU && (show_cpu || show_all)) {
assert(mem_proc != 0 && cpu_proc == 0);
get_cpu_usage(cpu_cores, cpuinfo, cpu_utils, i, tdelay / 2);
write(q[1], cpuinfo, PANE_BUF);
raise(SIGSTOP);
}
// Display cores info
if (id == MAIN) {
if (show_mem || show_cpu || show_all) {
usleep(tdelay);
}
draw_reset(samples, tdelay);
if (show_mem || show_all) {
// printf("main wait to read mem\n");
read(p[0], meminfo, PANE_BUF);
printf("%s", meminfo);
if (kill(mem_proc, SIGCONT) != 0) {
perror("kill");
exit(1);
};
}
if (show_cpu || show_all) {
read(q[0], cpuinfo, PANE_BUF);
printf("%s", cpuinfo);
if (kill(cpu_proc, SIGCONT) != 0) {
perror("kill");
exit(1);
};
}
if (show_cores || show_all) {
// The core info had time to generate, now it should read without
// generation time
if (i == 0) {
read(r[0], coreinfo, PANE_BUF);
}
printf("%s", coreinfo);
}
}
}
return 0;
}