CS3413/Assignment5/hard_affinity.c

191 lines
6.2 KiB
C
Raw Normal View History

2023-10-27 10:42:23 -03:00
#include <stdio.h>
2023-10-27 11:24:40 -03:00
#include <pthread.h>
2023-10-27 12:23:06 -03:00
#include <semaphore.h>
#include <stdlib.h>
2023-10-27 10:42:23 -03:00
#include "lib/queue.h"
2023-10-27 12:23:06 -03:00
// TODO: Look into semaphore increment too much in print function, look into synchronization
2023-10-27 10:42:23 -03:00
#define MAX_USERNAME_LENGTH 100
int QUANTUM;
2023-10-27 11:24:40 -03:00
int CPUS;
2023-10-27 12:23:06 -03:00
int TIME = 0;
// Semaphore for the print function
sem_t print_semaphore;
typedef struct ThreadArgs {
int cpu_id;
char *print_buffer;
Queue *summary_queue;
Queue *in_queue;
} ThreadArgs;
ThreadArgs *createArgs(int cpu_id, char* print_buffer, Queue *summary_queue, Queue *in_queue) {
ThreadArgs *args = malloc(sizeof(ThreadArgs));
args->cpu_id = cpu_id;
args->print_buffer = print_buffer;
args->summary_queue = summary_queue;
args->in_queue = in_queue;
return args;
}
2023-10-27 10:42:23 -03:00
Queue *input_queue() {
Queue *queue = createQueue();
char username[MAX_USERNAME_LENGTH]; // username buffer
char job;
2023-10-27 11:24:40 -03:00
int arrival_time, duration, affinity;
2023-10-27 10:42:23 -03:00
scanf("%d", &QUANTUM);
while (getchar() != '\n'); // clear the newline from the buffer
2023-10-27 11:24:40 -03:00
scanf("%d", &CPUS);
while (getchar() != '\n'); // clear the newline from the buffer
2023-10-27 12:23:06 -03:00
// Make sure sem is init right after getting cpus
sem_init(&print_semaphore, 0, CPUS); // Initialize the semaphore
2023-10-27 11:24:40 -03:00
while (getchar() != '\n'); // ignore the rest of the line, this is the table line
2023-10-27 10:42:23 -03:00
// Loop through the process table and enqueue each process
2023-10-27 11:24:40 -03:00
while (scanf("%99s %c %d %d %d", username, &job, &arrival_time, &duration, &affinity) != EOF) {
Process *process = createProcess(username, job, arrival_time, duration, affinity);
2023-10-27 10:42:23 -03:00
enqueue(queue, process);
}
return queue;
}
2023-10-27 12:23:06 -03:00
void* print(void *args) {
// Cast args and create local variables
ThreadArgs *thread_args = (ThreadArgs*) args;
char *print_buffer = thread_args->print_buffer;
Queue *summary_queue = thread_args->summary_queue;
Queue *in_queue = thread_args->in_queue;
2023-10-27 11:24:40 -03:00
// Print the Time label as well as the CPU labels
printf("Time");
for (int i = 0; i < CPUS; i++) {
printf("\tCPU%d", i);
}
printf("\n");
2023-10-27 10:42:23 -03:00
2023-10-27 12:23:06 -03:00
for (int i = 0; i < in_queue->size; ++i) {
TIME++;
// Allow the simulation to begin
sem_post(&print_semaphore);
2023-10-27 11:24:40 -03:00
2023-10-27 12:23:06 -03:00
for (int j = 0; j < CPUS; ++j) {
printf("%d\t%c", TIME, print_buffer[i]);
}
printf("\n");
}
// Print the summary
printf("\nSummary\n");
printList(summary_queue);
2023-10-27 11:24:40 -03:00
2023-10-27 12:23:06 -03:00
return NULL;
2023-10-27 11:24:40 -03:00
}
2023-10-27 12:23:06 -03:00
void* simulation(void *args) {
// Cast args and create local variables
ThreadArgs *thread_args = (ThreadArgs*) args;
Queue *in_queue = thread_args->in_queue;
Queue *summary_queue = thread_args->summary_queue;
char *print_buffer = thread_args->print_buffer;
int cpu_id = thread_args->cpu_id;
2023-10-27 11:24:40 -03:00
2023-10-27 10:42:23 -03:00
// Loop variables
int quantum = QUANTUM;
int addedJobs = 0;
2023-10-27 12:23:06 -03:00
Process *process = NULL;
2023-10-27 10:42:23 -03:00
// Create a queue for the simulation
Queue *sim_queue = createQueue();
while (true) {
2023-10-27 12:23:06 -03:00
sem_wait(&print_semaphore); // Wait for the print semaphore
2023-10-27 10:42:23 -03:00
// Begin going through all jobs and enqueueing them if they have arrived
process = in_queue->end;
for (int i = 0; i < in_queue->size; i++) {
2023-10-27 12:23:06 -03:00
if (process->affinity == cpu_id && process->arrival_time == TIME) {
2023-10-27 10:42:23 -03:00
// Create copy to keep the queues separate
2023-10-27 11:24:40 -03:00
Process *copy = createProcess(process->username, process->job, process->arrival_time, process->duration, process->affinity);
2023-10-27 10:42:23 -03:00
enqueue(sim_queue, copy);
addedJobs++;
}
process = process->prev_elem;
}
// Begin printing the current job
process = sim_queue->end;
2023-10-27 12:23:06 -03:00
if (sim_queue->size == 0) { //If there is nothing in sim_queue, put '-' in the print buffer
print_buffer[cpu_id] = '-';
2023-10-27 10:42:23 -03:00
if (addedJobs == in_queue->size) {
break; // If all jobs have been added, and the simulation queue is empty, then we are done
}
} else {
2023-10-27 12:23:06 -03:00
print_buffer[cpu_id] = process->job;
2023-10-27 10:42:23 -03:00
process->duration--;
quantum--;
if (process->duration == 0) { // If the process is done, delete it
Process *temp = dequeue(sim_queue); // Store the process in a temp variable for deletion
2023-10-27 12:23:06 -03:00
search(summary_queue, temp->username)->finish_time = TIME; // Set the finish time for the summary queue
2023-10-27 10:42:23 -03:00
destroyProcess(temp); // This should be called on every process
quantum = QUANTUM; // Make sure to reset the quantum when a process is done
} else if (quantum == 0) { // If the quantum is 0, then we need to dequeue the process and enqueue it again
process = dequeue(sim_queue);
enqueue(sim_queue, process);
quantum = QUANTUM;
}
}
}
// Free memory for the simulation queue. There should be nothing left in it
stop(sim_queue);
2023-10-27 12:23:06 -03:00
return NULL;
2023-10-27 10:42:23 -03:00
}
2023-10-27 12:23:06 -03:00
2023-10-27 10:42:23 -03:00
int main() {
Queue *in_queue = input_queue(); // Create the input queue
2023-10-27 12:23:06 -03:00
Queue *summary_queue = createQueue(); // Create the summary queue
char *print_buffer = malloc(sizeof(char) * CPUS); // Create the print buffer
// Summary creation
Process *process = in_queue->end;
for (int i = 0; i < in_queue->size; ++i) {
if (contains(summary_queue, process->username) == false) {
Process *copy = createProcess(process->username, process->job, process->arrival_time, process->duration, process->affinity);
enqueue(summary_queue, copy);
}
process = process->prev_elem;
}
2023-10-27 11:24:40 -03:00
// Create the print thread
pthread_t print_thread;
2023-10-27 12:23:06 -03:00
ThreadArgs *print_args = createArgs(0, print_buffer, summary_queue, in_queue);
pthread_create(&print_thread, NULL, &print, print_args);
2023-10-27 11:24:40 -03:00
// Create the simulation threads
pthread_t threads[CPUS];
2023-10-27 12:23:06 -03:00
ThreadArgs* args[CPUS]; // Array of arguments for each thread, so we can free them later
2023-10-27 11:24:40 -03:00
for (int i = 0; i < CPUS; i++) {
2023-10-27 12:23:06 -03:00
args[i] = createArgs(i, print_buffer, summary_queue, in_queue);
pthread_create(&threads[i], NULL, &simulation, args[i]);
2023-10-27 11:24:40 -03:00
}
// This should make sure all threads are done simulating, as the print function exits after simulation is done
pthread_join(print_thread, NULL);
// Just to make sure all threads are done
for (int i = 0; i < CPUS; i++) {
pthread_join(threads[i], NULL);
2023-10-27 12:23:06 -03:00
free(args[i]);
2023-10-27 11:24:40 -03:00
}
2023-10-27 10:42:23 -03:00
stop(in_queue); // Free memory for input queue
2023-10-27 12:23:06 -03:00
stop(summary_queue); // Free memory for summary queue
free(print_buffer); // Free memory for print buffer
2023-10-27 10:42:23 -03:00
return 0;
}