-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdriver.c
More file actions
401 lines (363 loc) · 16.1 KB
/
driver.c
File metadata and controls
401 lines (363 loc) · 16.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
#define _POSIX_C_SOURCE 200809L //the manpage tells u to use this macro with this version(i found version on stackoverflow)
#include <unistd.h>
#include <stdio.h> // standard i/o
#include <stdlib.h> //standard library
#include <string.h> //for strcmp and other string fxn
#include <signal.h> // to catch signal
#include <termios.h> // this pauses input from going to the terminal
#include <sys/wait.h> // this is word the wait() fxn
#include <fcntl.h> // For fcntl(), reference #5
#include "info.h" // CpuInfo, getCpuUsage(), and other calculation fxns
#include "printing.h" // displayParameter(), getAllSamples(), and other display fxns
volatile sig_atomic_t sigint_flag = 0; //this is a flag for the singal handler (reference #6)
typedef struct pid { //this struct has all the pid for different processes
pid_t pid_cpu; // cpu pid, then mem, then core, then freq
pid_t pid_mem;
pid_t pid_core;
pid_t pid_freq;
} Pid_child;
void handler_sigint(int sig) {
///_|> descry: this function sets the flag to 1
///_|> sig: (int) signal
///_|> returning: returns nothing
sigint_flag = 1;
}
void checkChildProcess(Pid_child *pid) {
///_|> descry: this function stops the child processes if flag is set to 1, then continues them
///_|> Pid_child pid: this is a pointer type to a struct of pid
///_|> returning: returns nothing
if (sigint_flag == 1) { //checks if flag is 1
if (pid->pid_core > 0) { //checks each pid if it is a process, then stops it with SIGSTOP
kill(pid->pid_core, SIGSTOP); // this is from reference #10
}
if (pid->pid_cpu > 0) {
kill(pid->pid_cpu, SIGSTOP);
}
if (pid->pid_freq > 0) {
kill(pid->pid_freq, SIGSTOP);
}
if (pid->pid_mem > 0) {
kill(pid->pid_mem, SIGSTOP);
}
char input; //input
printf("\n\nPaused All Process\n");
printf("Do you want to exit? (y/n): ");
fflush(stdout); //flsuh output
input = getchar(); //get input
if (input == 'y') {
printf("\nTerminated\n");
exit(0);
} else {
printf("\033[A\033[2K"); // escape code to delete line and go up 4 times
printf("\033[A\033[2K");
printf("\033[A\033[2K");
printf("\033[A\033[2K");
fflush(stdout);
sigint_flag = 0; //set flag back to 0
if (pid->pid_core > 0) { // if processes exist, then continue with SIGCONT
kill(pid->pid_core, SIGCONT); //from reference #10, same with below
}
if (pid->pid_cpu > 0) {
kill(pid->pid_cpu, SIGCONT);
}
if (pid->pid_freq > 0) {
kill(pid->pid_freq, SIGCONT);
}
if (pid->pid_mem > 0) {
kill(pid->pid_mem, SIGCONT);
}
}
}
}
int main(int argc, char **argv)
{
///_|> descry: this function parses the cla and then creates process depending on the flags
///_|> argc: (int) number of cla
///_|> argv: (char**) cla array of strings
///_|> returning: returns 0 at the end of the program
struct sigaction newact; // sigaction struct as shown in lecture
newact.sa_handler = handler_sigint; // this is a custom handler that sets flag
newact.sa_flags = 0;
sigemptyset(&newact.sa_mask); //
sigaction(SIGINT, &newact, NULL); //apply handler to sigint (ctrl+c)
struct sigaction newact2;
newact2.sa_handler = SIG_IGN; //from man page (ignores signal) ref #4
newact2.sa_flags = 0;
sigemptyset(&newact2.sa_mask);
sigaction(SIGTSTP, &newact2, NULL); //applies handler to sigstp (ctrl+z)
struct termios terminal; //declare termios struct
tcgetattr(STDIN_FILENO, &terminal); //termios struct set to file descriptor
terminal.c_cc[VSUSP] = _POSIX_VDISABLE; // this disables ctrl+z command from suspending
tcsetattr(STDIN_FILENO, TCSANOW, &terminal); // change attribute for teminal immediately
// ^this is the only way I found to not let ctrl+z input disturb my graph
// ref #11 stack overflow for the code above
// setting flags
int memoryFlag = 0;
int cpuFlag = 0;
int coresFlag = 0;
int samplesFlag = 0;
int tdelayFlag = 0;
int defaultSamples = 20;
int defaultDelay = 500000;
//looping thorugh clas
for (int i = 1; i < argc; i++)
{
if (strcmp(argv[i], "--memory") == 0)
{
memoryFlag = 1;
}
else if (strcmp(argv[i], "--cpu") == 0)
{
cpuFlag = 1;
}
else if (strcmp(argv[i], "--cores") == 0)
{
coresFlag = 1;
}
else if (strncmp(argv[i], "--samples", 9) == 0)
{
sscanf(argv[i], "--samples=%d", &defaultSamples);
samplesFlag = 1;
}
else if (strncmp(argv[i], "--tdelay", 8) == 0)
{
sscanf(argv[i], "--tdelay=%d", &defaultDelay);
tdelayFlag = 1;
}
else
{
if (defaultSamples == 20 && samplesFlag == 0)
{
defaultSamples = atoi(argv[i]);
samplesFlag = 1;
}
else if (defaultDelay == 500000 && tdelayFlag == 0)
{
defaultDelay = atoi(argv[i]);
tdelayFlag = 1;
}
}
}
//clear screen
printf("\033[H\033[J\n");
displayParameter(defaultSamples, defaultDelay); // display header
printf("\n");
int p_cpu[2]; //create pipe var for cpu graph func
int p_mem[2]; //create pipe var for mem graph func
int p_core[2]; //create pipe var for core func
int p_freq[2]; // create pipe var for freq func
Pid_child pid;
if (pipe(p_cpu) == -1) { //creating pipe and checking for error
perror("pipe cpu");
exit (1);
}
if (pipe(p_mem) == -1) { //creating pipe and checking for error
perror("pipe mem");
exit (1);
}
if (pipe(p_core) == -1) { //creating pipe and checking for error
perror("pipe core");
exit (1);
}
if (pipe(p_freq) == -1) { // creating pipe and checking for error
perror("pipe freq");
exit (1);
}
// if no argument or only positional then enable all flags
if (argc < 2 || (memoryFlag == 0 && cpuFlag == 0 && coresFlag == 0)) {
memoryFlag = 1;
cpuFlag = 1;
coresFlag = 1;
}
if (memoryFlag == 1 && cpuFlag == 1) { //if both cpu and memory
pid.pid_mem = fork(); //fork process
if (pid.pid_mem == 0) { //in child process
signal(SIGTSTP, SIG_IGN); //ignore sigstp
close(p_mem[0]); //closing read of child process pipe since only need to write
dup2(p_mem[1], STDOUT_FILENO); // redirect stdout to pipe write(reference #4)
for (int i = 0; i < defaultSamples; i++) { //loop through samples and write memory o pipe
float usedMemory = getUsedMemory();
write(STDOUT_FILENO, &usedMemory, sizeof(float));
usleep(defaultDelay); //delay is required
}
printf("\n");
close(p_mem[1]); //close pipe write after done using
exit(0);
}
pid.pid_cpu = fork(); //fork process
if (pid.pid_cpu == 0) { //child process
signal(SIGTSTP, SIG_IGN); //ignore sigstp
close(p_cpu[0]); //closing read of child process pipe since only need to write
dup2(p_cpu[1], STDOUT_FILENO); // redirect stdout to pipe write(reference #4)
for (int i = 0; i < defaultSamples; i++) { //loop through samples amount and write cpuUsage every sample
float usedCpu = getCpuUsage(defaultDelay);
write(STDOUT_FILENO, &usedCpu, sizeof(float));
}
close(p_cpu[1]); //close pipe write after done using
exit(0);
}
}
else if (memoryFlag == 1)
{
pid.pid_mem = fork(); //fork process
if (pid.pid_mem == 0) { //if child
signal(SIGTSTP, SIG_IGN); //ignore ststp
close(p_mem[0]); //closing read of child process pipe since only need to write
dup2(p_mem[1], STDOUT_FILENO); // redirect stdout to pipe write(reference #4)
getMemoryPerSample(defaultSamples, defaultDelay); //call memory sample
close(p_mem[1]); //close pipe write after done using
exit(0);
}
}
else if (cpuFlag == 1)
{
pid.pid_cpu = fork(); // fork process
if (pid.pid_cpu == 0) { // check for child
signal(SIGTSTP, SIG_IGN);
close(p_cpu[0]); //closing read of child process pipe since only need to write
dup2(p_cpu[1], STDOUT_FILENO); // redirect stdout to pipe write(reference #4)
getCpuUsagePerSample(defaultSamples, defaultDelay); //cpu usage function
close(p_cpu[1]); //close pipe write after done using
exit(0);
}
}
if (coresFlag == 1)
{
pid.pid_core = fork(); //fork proceess
if (pid.pid_core == 0) { //check for child
signal(SIGTSTP, SIG_IGN);
//printf("Child (core) process created! PID: %d\n", getpid());
close(p_core[0]); //closing read of child process pipe since only need to write
int cores = parseCpuCore();
write(p_core[1], &cores, sizeof(int)); //write core value to pipe
close(p_core[1]); //close pipe write after done using
exit(0);
}
pid.pid_freq = fork(); //fork process
if (pid.pid_freq == 0) { //check for child
signal(SIGTSTP, SIG_IGN);
//printf("Child (frequency) process created! PID: %d\n", getpid());
close(p_freq[0]); //closing read of child process pipe since only need to write
float frequency = parseCpuFreq();
write(p_freq[1], &frequency, sizeof(float)); //write frequency value to pipe
close(p_freq[1]); //close pipe write after done using
exit(0);
}
}
//below is my read part where the program reads every pipe sequentially
if (cpuFlag == 1 && memoryFlag == 1) //if both cpu and memory flag
{
close(p_mem[1]); //close parent write end
close(p_cpu[1]); //same as above
// the code below is from ref #12
//this code uses fcntl() to make sure pipe has info before reading it
// these 2 lines are from stackoverflow
fcntl(p_mem[0], F_SETFL, fcntl(p_mem[0], F_GETFL, 0) | O_NONBLOCK);
fcntl(p_cpu[0], F_SETFL, fcntl(p_cpu[0], F_GETFL, 0) | O_NONBLOCK);
float arrMem[defaultSamples]; //define memory and cpu array
float arrCPU[defaultSamples];
int j = 1; //number of samples in array
printf("v Memory %.2f GB\n", getUsedMemory()); // print the graph header
printf("\033[s"); // save cursor
float memVal = -1; //set flags and vals for mem and cpu
float cpuVal = -1;
int mem_FLAG = 0;
int cpu_FLAG = 0;
while (j <= defaultSamples) { //loop thorugh all samples
if (mem_FLAG == 0) { //checks if there is something to read
if (read(p_mem[0], &memVal, sizeof(float)) == 4) { //check if reads 4 bytes
mem_FLAG = 1;
}
}
if (cpu_FLAG == 0) { //checks if there is something to read
if (read(p_cpu[0], &cpuVal, sizeof(float)) == 4) { //checks if it reads 4 bytes
cpu_FLAG = 1;
}
}
// check if both values are there and then reset flags
if (mem_FLAG == 1 && cpu_FLAG == 1)
{
arrMem[j-1] = memVal; //populates arrays with value that was read
arrCPU[j-1] = cpuVal;
printf("\033[u"); // restore cursor
printMemory(arrMem, defaultSamples, j); //print memory graph
printf("\n");
printf("v CPU %.2f %%\n", cpuVal);
printCpuUsage(arrCPU, defaultSamples, j); //print cpu graph
fflush(stdout);
j++; //incremnt array size
mem_FLAG = 0; //reset flags
cpu_FLAG = 0;
}
checkChildProcess(&pid); //check for sigint in child
}
printf("\n");
close(p_mem[0]); //close pipes for reading
close(p_cpu[0]);
waitpid(pid.pid_mem, NULL, 0); //waitpid to make sure child is closed
waitpid(pid.pid_cpu, NULL, 0); //this is so no zombie processes are left
}
else if (memoryFlag == 1) { //check memory flag
close(p_mem[1]);
// the code below is from ref #12
//this code uses fcntl() to make sure pipe has info before reading it
// these 2 lines are from stackoverflow
fcntl(p_mem[0], F_SETFL, fcntl(p_mem[0], F_GETFL, 0) | O_NONBLOCK);
char buf[1024]; //create buffer
int nbytes;
while (1) {
pid_t result = waitpid(pid.pid_mem, NULL, WNOHANG); // waits until child is done, then exits
if (result == pid.pid_mem) { //if result is 0, then break
break;
}
nbytes = read(p_mem[0], buf, sizeof(buf)); //read from pipe to buffer
if (nbytes > 0) { //if something was read then write to output
write(STDOUT_FILENO, buf, nbytes);
}
checkChildProcess(&pid); //check for sigint in child
}
close(p_mem[0]); //close parent read pipe (pipe is closed)
}
else if (cpuFlag == 1) {
close(p_cpu[1]);
// the code below is from ref #12
//this code uses fcntl() to make sure pipe has info before reading it
// these 2 lines are from stackoverflow
fcntl(p_cpu[0], F_SETFL, fcntl(p_cpu[0], F_GETFL, 0) | O_NONBLOCK);
char buf[1024]; //create buffer
int nbytes;
while (1) {
pid_t result = waitpid(pid.pid_cpu, NULL, WNOHANG); // waits until child is done, then exits
if (result == pid.pid_cpu) { //if result is 0, then break
break;
}
nbytes = read(p_cpu[0], buf, sizeof(buf)); //read from pipe to buffer
if (nbytes > 0) { //if something was read then write to output
write(STDOUT_FILENO, buf, nbytes);
}
checkChildProcess(&pid); //check for sigint in child
}
close(p_cpu[0]); //close parent read pipe (pipe is closed)
}
if (coresFlag == 1) {
CpuInfo info; //deine cpu struct
//below is core reading
close(p_core[1]); //close parent write pipe
int cores;
read(p_core[0], &cores, sizeof(int)); //read pipe from parent side
info.cores = cores;
close(p_core[0]); //close parent side read pipe
waitpid(pid.pid_core, NULL, 0); //wait for child to finsih
checkChildProcess(&pid); //check for sigint in child
//below is frequency reading
close(p_freq[1]); // close parent write pipe
float frequency;
read(p_freq[0], &frequency, sizeof(float)); //read pipe from parent side
info.frequency = frequency;
close(p_freq[0]); //close parent read
waitpid(pid.pid_freq, NULL, 0); //wait for child to finish
checkChildProcess(&pid); //cehck for sigint in child process
printf("v Number of Cores: %d @ %.2f GHz\n", info.cores, info.frequency); //print statement
printCores(info.cores); //print core amount drawing
}
}