first commit

This commit is contained in:
bgraansm
2017-08-26 08:47:15 -04:00
commit 29775b66b5
11 changed files with 844 additions and 0 deletions

27
README.txt Normal file
View File

@@ -0,0 +1,27 @@
CIS3110 Assignment 2
author: Bronson Graansma, 0872249
date: Sunday, March 13th, 2016
contact: bgraansm@mail.uoguelph.ca
course: CIS*3110 Operating Systems I
__________________________________________________________________
For documentation on any of the function's functionality,
view function headers in *.h or *.c.
__________________________________________________________________
**Assumptions, Limitations, and Testing**
__________________________________________________________________
Assumes input file is redirected to stdin.
Assumes input file contains only integers, spaces or tabs
Assumes input file is in proper format
If any of the above assumptions are violated, program
receives a short message to stderr before terminating
Assumes command line arguments (if any exist) are among:
-v, -d, (-r x) in any order. -r must be followed directly
by some integer value (x). Any unrecognized flags will cause
the program to terminate with a message on stderr.
Assumes system has sufficient memory in order to run the program.
Memory allocations are checked with assert. Program will
terminate if an assertion fails and NDEBUG isn't defined.

15
input.txt Normal file
View File

@@ -0,0 +1,15 @@
2 3 7
1 2
1 0 3
1 10 20
2 10 20
3 10
2 5 2
1 50 10
2 50
2 2
1 0 1
1 100
2 50 2
1 100 20
2 100

13
main.c Normal file
View File

@@ -0,0 +1,13 @@
#include "mode.h"
#include "schedule.h"
#include "simulation.h"
int main(int argc, char** argv) {
Mode mode = newMode(argv, argc);
Schedule schedule = readSchedule(stdin);
simulate(schedule, mode);
freeSchedule(schedule);
return EXIT_SUCCESS;
}

8
makefile Normal file
View File

@@ -0,0 +1,8 @@
CC = gcc
CFLAGS = -Wall -pedantic -std=c99 -g
simcpu: main.c schedule.c mode.c simulation.c
$(CC) $(CFLAGS) $^ -o $@
clean:
rm -f *.o simcpu

89
mode.c Normal file
View File

@@ -0,0 +1,89 @@
#include "mode.h"
/* Creates a new mode to run the simulation in. Handles any errors
* with a useful message to stderr, and terminated the program.
* args: command line arguments to parse into the mode
* returns: a mode that signifies such things as:
* RR, quantum, verbose, detailed */
Mode newMode(char** argv, int argc) {
Mode new;
new.detailed = false;
new.verbose = false;
new.roundRobin = false;
new.quantum = 0;
for(int i=1; i<argc; i++) {
if(strcmp(argv[i], "-r") == 0) {
new.roundRobin = true;
if(i < argc-1) {
if(isInt(argv[i+1])) {
new.quantum = atol(argv[i+1]);
if(new.quantum < 1) {
fprintf(stderr, "This won't accomplish anything.\n");
exit(EXIT_FAILURE);
}
i++;
} else {
fprintf(stderr, "Quantum value must be an integer.\n");
exit(EXIT_FAILURE);
}
} else {
fprintf(stderr, "Round robin flag must be followed by a quantum value.\n");
exit(EXIT_FAILURE);
}
} else if(strcmp(argv[i], "-d") == 0) {
new.detailed = true;
} else if(strcmp(argv[i], "-v") == 0) {
new.verbose = true;
} else {
fprintf(stderr, "Usage: %s [-d] [-v] [-r quantum]\n", argv[0]);
exit(EXIT_FAILURE);
}
}
return new;
}
/* Checks to see if a string can be converted to an integer.
* args: the string to check
* returns: true if string is an int, false otherwise */
bool isInt(char* str) {
int len = 0;
if(!str) {
return false;
} else if((len = strlen(str)) < 1) {
return false;
}
for(int i=0; i<len; i++) {
if(!isdigit(str[i])) {
if(i == 0 && str[i] == '-') {
continue;
}
return false;
}
}
return true;
}
/* Checks if a string is empty or not
* args: the string to check
* returns: true if all characters are whitespace, false otherwise */
bool isEmpty(char* str) {
int len = 0;
if(!str) {
return false;
} else if((len = strlen(str)) < 1) {
return false;
}
for(int i=0; i<len; i++) {
if(!isspace(str[i])) {
return false;
}
}
return true;
}

34
mode.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef __MODE_H_
#define __MODE_H_
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Mode {
bool detailed;
bool verbose;
bool roundRobin;
int quantum;
} Mode;
/* Creates a new mode to run the simulation in. Handles any errors
* with a useful message to stderr, and terminated the program.
* args: command line arguments to parse into the mode
* returns: a mode that signifies such things as:
* RR, quantum, verbose, detailed */
Mode newMode(char** argv, int argc);
/* Checks to see if a string can be converted to an integer.
* args: the string to check
* returns: true if string is an int, false otherwise */
bool isInt(char* str);
/* Checks if a string is empty or not
* args: the string to check
* returns: true if all characters are whitespace, false otherwise */
bool isEmpty(char* str);
#endif

281
schedule.c Normal file
View File

@@ -0,0 +1,281 @@
#include "schedule.h"
static bool readBurst(FILE* fp, Burst* burst) {
char buffer[BUFF_LEN];
if(!burst) {
return false;
}
if(fgets(buffer, BUFF_LEN-1, fp)) { buffer[strlen(buffer)-1] = '\0';
char* token = strtok(buffer, " \t");
int ntokens = 0;
while(token) {
if(isEmpty(token)) {
token = strtok(NULL, " \t");
continue;
} else if(isInt(token)) {
switch(ntokens) {
case 0: burst->burstNum = atol(token); break;
case 1: burst->cpuTime = atol(token); break;
case 2: burst->ioTime = atol(token); break;
default: return false;
}
} else {
return false;
}
ntokens++;
token = strtok(NULL, " \t");
}
if(ntokens == 2) {
burst->ioTime = 0;
} else if(ntokens != 3) {
return false;
}
} else {
return false;
}
return true;
}
static bool readThread(FILE* fp, Thread* thread) {
char buffer[BUFF_LEN];
Burst* brst = NULL;
Burst* prev = NULL;
if(!thread) {
return false;
}
thread->burst = malloc(sizeof(Burst));
assert(thread->burst);
brst = thread->burst;
if(fgets(buffer, BUFF_LEN-1, fp)) { buffer[strlen(buffer)-1] = '\0';
char* token = strtok(buffer, " \t");
int ntokens = 0;
while(token) {
if(isEmpty(token)) {
token = strtok(NULL, " \t");
continue;
} else if(isInt(token)) {
switch(ntokens) {
case 0: thread->threadNum = atol(token); break;
case 1: thread->arriveTime = atol(token); break;
case 2: thread->nbursts = atol(token); break;
default: return false;
}
} else {
return false;
}
ntokens++;
token = strtok(NULL, " \t");
}
if(ntokens != 3) {
return false;
}
} else {
return false;
}
for(int i=0; i<thread->nbursts; i++) {
if(readBurst(fp, brst)) {
brst->next = malloc(sizeof(Burst));
assert(brst->next);
prev = brst;
brst = brst->next;
} else {
return false;
}
}
if(thread->nbursts == 0) {
free(thread->burst);
thread->burst = NULL;
} else {
free(brst);
prev->next = NULL;
}
thread->data.serviceTime = 0;
thread->data.ioTime = 0;
thread->data.turnAroundTime = 0;
thread->data.finishTime = 0;
return true;
}
static bool readProcess(FILE* fp, Process* process) {
char buffer[BUFF_LEN];
Thread* thrd = NULL;
Thread* prev = NULL;
if(!process) {
return false;
}
process->thread = malloc(sizeof(Thread));
assert(process->thread);
thrd = process->thread;
if(fgets(buffer, BUFF_LEN-1, fp)) { buffer[strlen(buffer)-1] = '\0';
char* token = strtok(buffer, " \t");
int ntokens = 0;
while(token) {
if(isEmpty(token)) {
token = strtok(NULL, " \t");
continue;
} else if(isInt(token)) {
switch(ntokens) {
case 0: process->processNum = atol(token); break;
case 1: process->nthreads = atol(token); break;
default: return false;
}
} else {
return false;
}
ntokens++;
token = strtok(NULL, " \t");
}
if(ntokens != 2) {
return false;
}
} else {
return false;
}
for(int i=0; i<process->nthreads; i++) {
if(readThread(fp, thrd)) {
thrd->next = malloc(sizeof(Thread));
assert(thrd->next);
prev = thrd;
thrd = thrd->next;
} else {
return false;
}
}
if(process->nthreads == 0) {
free(process->thread);
process->thread = NULL;
} else {
free(thrd);
prev->next = NULL;
}
return true;
}
/* reads input from a stream to create a schedule
* args: the stream to read from
* returns: a schedule with specs from file */
Schedule readSchedule(FILE* fp) {
Schedule schedule;
char buffer[BUFF_LEN];
Process* proc = NULL;
Process* prev = NULL;
schedule.nprocesses = 0;
schedule.switchSame = 0;
schedule.switchNew = 0;
schedule.process = NULL;
if(fp == NULL) {
fprintf(stderr, "Unable to read from file.\n");
exit(EXIT_FAILURE);
}
schedule.process = malloc(sizeof(Process));
assert(schedule.process);
proc = schedule.process;
while(fgets(buffer, BUFF_LEN-1, fp)) { buffer[strlen(buffer)-1] = '\0';
char* token = strtok(buffer, " \t");
int ntokens = 0;
while(token) {
if(isEmpty(token)) {
token = strtok(NULL, " \t");
continue;
} else if(isInt(token)) {
switch(ntokens) {
case 0: schedule.nprocesses = atol(token); break;
case 1: schedule.switchSame = atol(token); break;
case 2: schedule.switchNew = atol(token); break;
default:
fprintf(stderr, "Unexpected file contents.\n");
freeSchedule(schedule);
exit(EXIT_FAILURE);
}
} else {
fprintf(stderr, "Unexpected file contents.\n");
freeSchedule(schedule);
exit(EXIT_FAILURE);
}
ntokens++;
token = strtok(NULL, " \t");
}
if(ntokens != 3) {
fprintf(stderr, "Unexpected file contents.\n");
freeSchedule(schedule);
exit(EXIT_FAILURE);
}
for(int i=0; i<schedule.nprocesses; i++) {
if(readProcess(fp, proc)) {
proc->next = malloc(sizeof(Process));
assert(proc->next);
prev = proc;
proc = proc->next;
} else {
fprintf(stderr, "Unexpected file contents.\n");
freeSchedule(schedule);
exit(EXIT_FAILURE);
}
}
}
if(schedule.nprocesses == 0) {
fprintf(stderr, "Unexpected file contents.\n");
freeSchedule(schedule);
exit(EXIT_FAILURE);
} else {
free(proc);
prev->next = NULL;
}
return schedule;
}
static void freeBurst(Burst* burst) {
if(!burst) return;
freeBurst(burst->next);
free(burst);
}
static void freeThread(Thread* thread) {
if(!thread) return;
freeThread(thread->next);
freeBurst(thread->burst);
free(thread);
}
static void freeProcess(Process* process) {
if(!process) return;
freeProcess(process->next);
freeThread(process->thread);
free(process);
}
/* frees all memory allocated for the schedule
* args: the schedule to deallocate */
void freeSchedule(Schedule schedule) {
freeProcess(schedule.process);
}

132
schedule.h Normal file
View File

@@ -0,0 +1,132 @@
#ifndef __SCHEDULE_H_
#define __SCHEDULE_H_
#include "mode.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#define BUFF_LEN 1024
/*
Schedule schedule:
int nprocesses
int switchSame
int switchNew
Process* process:
int processNum
int nthreads
Process* next
Thread* thread:
int threadNum
int arriveTime
int nbursts
Thread* next
Burst* burst:
int burstNum
int cpuTime
int ioTime
Burst* next
Data data:
int serviceTime
int ioTime
int turnAroundTime
int finishTime
Queue queue:
int size
Event* event:
int ofProcess
int ready
Thread* thread:
int threadNum
int arriveTime
int nbursts
Thread* next
Burst* burst:
int burstNum
int cpuTime
int ioTime
Burst* next
Data data:
int serviceTime
int ioTime
int turnAroundTime
int finishTime
*/
typedef struct Data {
int serviceTime;
int ioTime;
int turnAroundTime;
int finishTime;
} Data;
typedef struct Burst {
int burstNum;
int cpuTime;
int ioTime;
struct Burst* next;
} Burst;
typedef struct Thread {
int threadNum;
int arriveTime;
int nbursts;
Burst* burst;
Data data;
struct Thread* next;
} Thread;
typedef struct Process {
int processNum;
int nthreads;
Thread* thread;
struct Process* next;
} Process;
typedef struct Schedule {
int nprocesses;
int switchSame;
int switchNew;
Process* process;
} Schedule;
typedef struct Event {
Thread* thread;
int ofProcess;
int ready;
} Event;
typedef struct Queue {
int size;
Event* event;
} Queue;
/* reads input from a stream to create a schedule
* args: the stream to read from
* returns: a schedule with specs from file */
Schedule readSchedule(FILE* fp);
/* frees all memory allocated for the schedule
* args: the schedule to deallocate */
void freeSchedule(Schedule schedule);
#endif

15
sim2.txt Normal file
View File

@@ -0,0 +1,15 @@
3 3 7
1 2
1 0 2
1 10 20
2 10
2 5 2
1 50 10
2 50
2 1
1 0 1
1 100
3 1
1 25 2
1 100 20
2 100

219
simulation.c Normal file
View File

@@ -0,0 +1,219 @@
#include "simulation.h"
/* compare function for qsort. sort queue on arrival times */
static int compareEvent(const void* event1, const void* event2) {
Event e1 = *(Event*)event1;
Event e2 = *(Event*)event2;
return (e1.ready > e2.ready) - (e1.ready < e2.ready);
}
/* create an initial queue from a fresh schedule */
static Queue newQueue(Schedule schedule) {
Queue queue = {.size = 0, .event = NULL};
Process* proc = schedule.process;
for(int i=0; i<schedule.nprocesses; i++) {
Thread* thread = proc->thread;
for(int j=0; j<proc->nthreads; j++) {
queue.event = realloc(queue.event, (queue.size+1)*sizeof(Event));
assert(queue.event);
queue.event[queue.size].thread = thread;
queue.event[queue.size].ofProcess = proc->processNum;
queue.event[queue.size].ready = thread->arriveTime;
queue.size++;
thread = thread->next;
}
proc = proc->next;
}
qsort(queue.event, queue.size, sizeof(Event), compareEvent);
return queue;
}
/* Simulates a cpu thread scheduler for rr or fcfs.
* args: the schedule to simulate, and the mode in which to simulate it */
void simulate(Schedule schedule, Mode mode) {
Queue queue = newQueue(schedule);
Process* proc = schedule.process;
char* verbose = malloc(1); verbose[0] = '\0';
int idle = 0;
int cpuTime = 0;
int timeSlice = 0;
int turnAround = 0;
int totalTime = 0;
int nthreads = 0;
if(mode.roundRobin) {
printf("Round Robin Scheduling (quantum = %d time units)\n", mode.quantum);
} else {
printf("First Come First Serve Scheduling\n");
}
for(int i=0; i<queue.size; i++) {
if(mode.verbose) {
char buff[BUFF_LEN];
int sysTime = timeSlice;
if(timeSlice <= queue.event[i].ready) {
sysTime = queue.event[i].ready;
}
sprintf(buff, "At time %d: Thread %d of Process %d moves from new to ready\n",
sysTime, queue.event[i].thread->threadNum, queue.event[i].ofProcess);
verbose = realloc(verbose, strlen(verbose)+strlen(buff)+1);
assert(verbose);
strcat(verbose, buff);
}
if(i > 0) { // context switch
if(queue.event[i].ofProcess == queue.event[i-1].ofProcess) {
if(queue.event[i].thread->threadNum == queue.event[i-1].thread->threadNum) {
//no overhead
} else {
timeSlice += schedule.switchSame;
idle += schedule.switchSame;
}
} else {
timeSlice += schedule.switchNew;
idle += schedule.switchNew;
}
}
if(timeSlice <= queue.event[i].ready) { // nothing waiting for the cpu
idle += queue.event[i].ready - timeSlice;
timeSlice = queue.event[i].ready; // advance the timer
}
if(mode.verbose) {
char buff[BUFF_LEN];
sprintf(buff, "At time %d: Thread %d of Process %d moves from ready to running\n",
timeSlice, queue.event[i].thread->threadNum, queue.event[i].ofProcess);
verbose = realloc(verbose, strlen(verbose)+strlen(buff)+1);
assert(verbose);
strcat(verbose, buff);
}
// run threads in queue's burst. then kick it out for io or quantum
if(mode.roundRobin) {
if(queue.event[i].thread->burst->cpuTime > mode.quantum) {
timeSlice += mode.quantum;
cpuTime += mode.quantum;
queue.event[i].thread->burst->cpuTime -= mode.quantum;
queue.event[i].thread->data.serviceTime += mode.quantum;
} else {
timeSlice += queue.event[i].thread->burst->cpuTime;
cpuTime += queue.event[i].thread->burst->cpuTime;
queue.event[i].thread->data.serviceTime += queue.event[i].thread->burst->cpuTime;
queue.event[i].thread->data.ioTime += queue.event[i].thread->burst->ioTime;
queue.event[i].thread->burst->cpuTime = 0;
}
} else {
timeSlice += queue.event[i].thread->burst->cpuTime;
cpuTime += queue.event[i].thread->burst->cpuTime;
queue.event[i].thread->data.ioTime += queue.event[i].thread->burst->ioTime;
queue.event[i].thread->data.serviceTime += queue.event[i].thread->burst->cpuTime;
}
queue.event[i].thread->data.turnAroundTime = timeSlice - queue.event[i].thread->arriveTime;
queue.event[i].thread->data.finishTime = timeSlice;
if(mode.roundRobin && queue.event[i].thread->burst->cpuTime > 0) {
queue.event = realloc(queue.event, (queue.size+1)*sizeof(Event));
assert(queue.event);
queue.event[queue.size] = queue.event[i];
queue.event[queue.size].ready = timeSlice;
queue.size++;
qsort(queue.event, queue.size, sizeof(Event), compareEvent);
if(mode.verbose) {
char buff[BUFF_LEN];
sprintf(buff, "At time %d: Thread %d of Process %d moves from running to blocked\n",
timeSlice, queue.event[i].thread->threadNum, queue.event[i].ofProcess);
verbose = realloc(verbose, strlen(verbose)+strlen(buff)+1);
assert(verbose);
strcat(verbose, buff);
}
continue;
}
// place unfinished threads back into the queue with their apropriate ready time
if(queue.event[i].thread->burst->next) {
Burst* temp = queue.event[i].thread->burst;
if(mode.verbose) {
char buff[BUFF_LEN];
sprintf(buff, "At time %d: Thread %d of Process %d moves from running to blocked\n",
timeSlice, queue.event[i].thread->threadNum, queue.event[i].ofProcess);
verbose = realloc(verbose, strlen(verbose)+strlen(buff)+1);
assert(verbose);
strcat(verbose, buff);
}
queue.event = realloc(queue.event, (queue.size+1)*sizeof(Event));
assert(queue.event);
queue.event[queue.size] = queue.event[i];
queue.event[queue.size].thread->burst = queue.event[queue.size].thread->burst->next;
queue.event[queue.size].ready = timeSlice + queue.event[i].thread->burst->ioTime;
queue.size++;
qsort(queue.event, queue.size, sizeof(Event), compareEvent);
free(temp);
} else if(mode.verbose) {
char buff[BUFF_LEN];
sprintf(buff, "At time %d: Thread %d of Process %d moves from running to terminated\n",
timeSlice, queue.event[i].thread->threadNum, queue.event[i].ofProcess);
verbose = realloc(verbose, strlen(verbose)+strlen(buff)+1);
assert(verbose);
strcat(verbose, buff);
}
}
// simulation is over, begin calculating and displaying stats
totalTime = timeSlice;
printf("Total Time required is %d time units.\n", totalTime);
for(int i=0; i<schedule.nprocesses; i++) {
Thread* thread = proc->thread;
for(int j=0; j<proc->nthreads; j++) {
turnAround += thread->data.turnAroundTime;
thread = thread->next;
nthreads++;
}
proc = proc->next;
}
printf("Average Turnaround Time is %d time units.\n", turnAround/nthreads);
printf("CPU Utilization is %.1f%%.\n", ((float)cpuTime/(float)totalTime)*100);
if(mode.detailed) {
proc = schedule.process;
printf("\n");
for(int i=0; i<schedule.nprocesses; i++) {
Thread* thread = proc->thread;
for(int j=0; j<proc->nthreads; j++) {
printf("Thread %d of Process %d:\n", thread->threadNum, proc->processNum);
printf(" arrival time: %d\n", thread->arriveTime);
printf(" service time: %d units, I/O time: %d units, turnaround time: %d units\n"
, thread->data.serviceTime, thread->data.ioTime, thread->data.turnAroundTime);
printf(" finish time: %d\n", thread->data.finishTime);
thread = thread->next;
}
proc = proc->next;
}
}
if(mode.verbose) {
printf("\n%s", verbose);
}
free(verbose);
free(queue.event);
}

11
simulation.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef _SIMULATION_H_
#define _SIMULATION_H_
#include "schedule.h"
#include "mode.h"
/* Simulates a cpu thread scheduler for rr or fcfs.
* args: the schedule to simulate, and the mode in which to simulate it */
void simulate(Schedule schedule, Mode mode);
#endif