diff --git a/code/Makefile b/code/Makefile index 51c2bb9..f518067 100644 --- a/code/Makefile +++ b/code/Makefile @@ -1,8 +1,10 @@ +.PHONY: build all clean test + build: gcc list.c queue.c process_generator.c -o process_generator.out gcc clk.c -o clk.out - gcc scheduler.c -o scheduler.out - gcc process.c -o process.out + gcc list.c scheduler.c -o scheduler.out + gcc list.c process.c -o process.out gcc test_generator.c -o test_generator.out clean: diff --git a/code/headers.h b/code/headers.h index 63ca5a0..2e26426 100644 --- a/code/headers.h +++ b/code/headers.h @@ -1,3 +1,4 @@ +#include #include #include #include //if you don't use scanf/printf change this include @@ -37,6 +38,9 @@ #define true 1 #define false 0 +// key proj_ids +#define SCH_GEN_COM 5 + #define SHKEY 300 ///============================== @@ -51,10 +55,9 @@ int *shmaddr; // queue *readInputFile(); void printBanner(); -enum scheduler_type getSchedulerType(); -void getInput(enum scheduler_type *, int *); -void clearResources(int); -void createSchedulerAndClock(pid_t *, pid_t *); +scheduler_type getSchedulerType(); +void getInput(scheduler_type *, int *); +void createSchedulerAndClock(pid_t *, pid_t *, int); void sendProcessesToScheduler(queue *, int); int intiSchGenCom(); @@ -85,10 +88,25 @@ void initClk() { * Input: terminateAll: a flag to indicate whether that this is the end of * simulation. It terminates the whole system and releases resources. */ - void destroyClk(bool terminateAll) { shmdt(shmaddr); if (terminateAll) { killpg(getpgrp(), SIGINT); } } + +void cleanUp() { + destroyClk(true); + killpg(getpgrp(), SIGINT); +} + +/** + * clearResources - Clears all resources in case of interruption. + * + * @signum: the signal number + */ +void clearResources(int signum) { + // TODO: Clears all resources in case of interruption + cleanUp(); + exit(0); +} diff --git a/code/keyfiles/SCH_GEN_COM b/code/keyfiles/SCH_GEN_COM new file mode 100644 index 0000000..e69de29 diff --git a/code/process.c b/code/process.c index 9a4fc6a..5685b06 100644 --- a/code/process.c +++ b/code/process.c @@ -1,9 +1,17 @@ #include "headers.h" /* Modify this file as needed*/ -int remainingtime; +int remainingtime = 1; int main(int agrc, char *argv[]) { + + signal(SIGINT, clearResources); + signal(SIGTERM, clearResources); + if (atexit(cleanUp) != 0) { + perror("atexit"); + exit(1); + } + initClk(); // TODO it needs to get the remaining time from somewhere diff --git a/code/process_generator.c b/code/process_generator.c index 74ca3b7..ba8402d 100644 --- a/code/process_generator.c +++ b/code/process_generator.c @@ -19,12 +19,17 @@ */ int main(int argc, char *argv[]) { queue *processes; - enum scheduler_type schedulerType; + scheduler_type schedulerType; int quantum; pid_t schedulerPid, clockPid; int msgQID; signal(SIGINT, clearResources); + signal(SIGTERM, clearResources); + if (atexit(cleanUp) != 0) { + perror("atexit"); + exit(1); + } printBanner(); @@ -33,14 +38,18 @@ int main(int argc, char *argv[]) { getInput(&schedulerType, &quantum); - createSchedulerAndClock(&schedulerPid, &clockPid); + createSchedulerAndClock(&schedulerPid, &clockPid, (int)schedulerType); initClk(); msgQID = intiSchGenCom(); sendProcessesToScheduler(processes, msgQID); - destroyQueue(processes); + + if (wait(NULL) == -1) { + perror("wait"); + exit(1); + } destroyClk(true); } @@ -54,7 +63,7 @@ queue *readInputFile() { FILE *file; char *line = NULL; size_t len = 0; - queue *processes = createQueue(); + queue *processes = createQueue(free); printf(ANSI_YELLOW "============================" ANSI_RESET "\n"); printf(ANSI_YELLOW "|| Reading processes file ||" ANSI_RESET "\n"); @@ -97,7 +106,7 @@ queue *readInputFile() { * * return: the chosen scheduler type */ -enum scheduler_type getSchedulerType() { +scheduler_type getSchedulerType() { int choice; printf(ANSI_TEAL "===========================================================" @@ -123,7 +132,7 @@ enum scheduler_type getSchedulerType() { case 3: return RR; default: - return -1; + exit(-1); } } @@ -134,7 +143,7 @@ enum scheduler_type getSchedulerType() { * @schedulerType: a pointer to the chosen scheduler type * @quantum: a pointer to the quantum value */ -void getInput(enum scheduler_type *schedulerType, int *quantum) { +void getInput(scheduler_type *schedulerType, int *quantum) { *schedulerType = getSchedulerType(); if (*schedulerType == -1) { @@ -214,7 +223,8 @@ void printBanner() { * @schedulerPid: a pointer to the scheduler process id * @clockPid: a pointer to the clock process id */ -void createSchedulerAndClock(pid_t *schedulerPid, pid_t *clockPid) { +void createSchedulerAndClock(pid_t *schedulerPid, pid_t *clockPid, + int schedulerType) { *clockPid = fork(); @@ -237,7 +247,23 @@ void createSchedulerAndClock(pid_t *schedulerPid, pid_t *clockPid) { } if (*schedulerPid == 0) { - char *args[] = {"./scheduler.out", NULL}; + char *type; + + switch (schedulerType) { + case 0: + type = "0"; + break; + case 1: + type = "1"; + break; + case 2: + type = "2"; + break; + default: + exit(-1); + } + + char *args[] = {"./scheduler.out", type, NULL}; execvp(args[0], args); exit(0); } @@ -247,18 +273,6 @@ void createSchedulerAndClock(pid_t *schedulerPid, pid_t *clockPid) { printf(ANSI_PURPLE "|| ==> Clock PID: %d\n" ANSI_RESET, *clockPid); } -/** - * clearResources - Clears all resources in case of interruption. - * - * @signum: the signal number - */ -void clearResources(int signum) { - // TODO: Clears all resources in case of interruption - destroyClk(true); - killpg(getpgrp(), SIGINT); - exit(0); -} - /** * sendProcessesToScheduler - Sends the processes to the scheduler at the * appropriate time. @@ -293,14 +307,20 @@ void sendProcessesToScheduler(queue *processes, int msgQID) { response = msgsnd(msgQID, process, sizeof(process_t), !IPC_NOWAIT); if (response == -1) { - fprintf(stderr, - ANSI_RED "==>Error in sending process to scheduler\n" ANSI_RESET); + perror("Error in sending process to scheduler\n"); exit(-1); } pop(processes); lastTime = currentTime; } + + process->id = -1; + response = msgsnd(msgQID, process, sizeof(process_t), !IPC_NOWAIT); + if (response == -1) { + perror("Error in terminating sending processes to scheduler\n"); + exit(-1); + } } /** @@ -310,7 +330,7 @@ void sendProcessesToScheduler(queue *processes, int msgQID) { * return: the message queue id */ int intiSchGenCom() { - int key = ftok("SCH_GEN_COM", 18); + int key = ftok("keyfiles/SCH_GEN_COM", SCH_GEN_COM); int msgQID = msgget(key, 0666 | IPC_CREAT); if (msgQID == -1) { diff --git a/code/scheduler.c b/code/scheduler.c index 3108180..7b2e23e 100644 --- a/code/scheduler.c +++ b/code/scheduler.c @@ -1,35 +1,172 @@ #include "headers.h" +#include "list.h" + +int msgQID; +d_list *p_table = NULL; + +void cleanUpScheduler() { + msgctl(msgQID, IPC_RMID, (struct msqid_ds *)0); + destroyClk(true); + if (p_table) + destroyList(&p_table); + killpg(getpgrp(), SIGINT); +} + +/** + * clearResources - Clears all resources in case of interruption. + * + * @signum: the signal number + */ +void clearSchResources(int signum) { + cleanUpScheduler(); + exit(0); +} + +scheduler_type getScType(int schedulerType) { + switch (schedulerType) { + case 0: + return HPF; + case 1: + return SRTN; + case 2: + return RR; + default: + exit(-1); + } +} + +void freeProcessEntry(void *processEntry) { + if (processEntry) + free(((process_entry_t *)processEntry)->PCB); + free(processEntry); +} + +void createProcess(d_list *processTable, process_t *process) { + pid_t pid; + process_entry_t *processEntry; + PCB_t *pcb; + + pid = fork(); + + if (pid == -1) { + perror("fork"); + exit(-1); + } + + if (pid == 0) { + char *args[] = {"./process.out", NULL}; + execvp(args[0], args); + exit(0); + } + + processEntry = malloc(sizeof(*processEntry)); + if (!processEntry) { + perror("malloc"); + exit(-1); + } + + pcb = malloc(sizeof(*pcb)); + if (!pcb) { + perror("malloc"); + exit(-1); + } + + pcb->state = READY; + pcb->process = *process; + processEntry->p_id = pid; + processEntry->PCB = pcb; + if (!insertNodeEnd(processTable, processEntry)) { + perror("insertNodeEnd"); + exit(-1); + } + + printf(ANSI_GREEN "==>SCH: Added process to processes table\n" ANSI_RESET); +} int main(int argc, char *argv[]) { - initClk(); + int key, gen_msgQID, response; + scheduler_type schedulerType; + process_t tmpProcess; + d_list *processTable = NULL; - // TODO implement the scheduler :) - // upon termination release the clock resources. + signal(SIGINT, clearSchResources); + signal(SIGTERM, clearSchResources); + if (atexit(cleanUpScheduler) != 0) { + perror("atexit"); + exit(1); + } - // init msgs queue with process generator + initClk(); - while (1) { - // TODO: change this later just for testing - int key = ftok("SCH_GEN_COM", 18); - int msgQID = msgget(key, 0666 | IPC_CREAT); + schedulerType = getScType(atoi(argv[1])); + printf(ANSI_YELLOW "==>SCH: My Scheduler Type is %i\n" ANSI_RESET, + (int)schedulerType); - if (msgQID == -1) { - perror("Error in creating message queue"); - exit(-1); - } + p_table = processTable = createList(freeProcessEntry); + if (!processTable) { + perror("Error while creating process table"); + exit(-1); + } - process_t process; + key = ftok("keyfiles/SCH_GEN_COM", SCH_GEN_COM); + msgQID = gen_msgQID = + msgget(key, 0666 | IPC_CREAT); // COM with process_generator - // FIXME: doesn't seem to be recieving the process check later - int response = msgrcv(msgQID, &process, sizeof(process_t), 0, !IPC_NOWAIT); + if (gen_msgQID == -1) { + perror("Error in creating message queue"); + exit(-1); + } + + while (1) { + response = + msgrcv(gen_msgQID, &tmpProcess, sizeof(process_t), 0, !IPC_NOWAIT); if (response == -1) { perror("Error in receiving process from process generator"); exit(-1); - } else { - printf(ANSI_BLUE "==>SCH: Received process" ANSI_RESET); } + + if (tmpProcess.id == -1) { + printf(ANSI_YELLOW "==>SCH: Received All Processes\n" ANSI_RESET); + break; + } + printf(ANSI_BLUE "==>SCH: Received process with id = %i\n" ANSI_RESET, + tmpProcess.id); + createProcess(processTable, &tmpProcess); } + msgctl(msgQID, IPC_RMID, (struct msqid_ds *)0); + + // TODO Initialize Scheduler + // Create Ready queue & (Wait queue ??) + // Create log file + // + // TODO Create process when generator tells you it is time + // Setup COM between process and Scheduler (init msgs queue) + // + // TODO Context Switch (print to log file in start and finish) + // When SRT process comes to ready queue (by myself) + // When quantem ends (communicate with clk) + // When a process finishes (process get SIGTRM) + // When a process gets a signal (SIGKILL, SIGINT, SIGSTP, ...etc) + // The Switch + // Move old process to ready or wait or (clear after, if it has terminated) + // Save PCB if it still exist (set attributes) + // Schedule new Process (We need the algo here) + // Load PCB (set attributes) + // Tell the process to start + // + // TODO Clear After process termination + // Calculate all needed values (till now) + // Remove process from processes Table (Delete its PCB) + // + // TODO Clean everything when Scheduler finishes or if it is killed + // Calculate all needed stats + // create pref file + // kill all living processes and destroy its PCB (is this right?) + // destroy process table + // destroy clk + // Any other clean up + destroyClk(true); } diff --git a/code/structs.h b/code/structs.h index 61f0357..4cd5cb0 100644 --- a/code/structs.h +++ b/code/structs.h @@ -1,5 +1,10 @@ // copyright 2024: Abderlrahman Samy - George Magdy - Ahmed Hamed - Amir Anwar +#include +typedef enum scheduler_type { HPF, SRTN, RR } scheduler_type; + +typedef enum process_state { READY, RUNNING, BLOCKED } process_state; + typedef struct process { int id; // unique identifier int AT; // arrival time @@ -8,4 +13,17 @@ typedef struct process { // TODO: add more attributes here when needed } process_t; -enum scheduler_type { HPF, SRTN, RR }; +typedef struct PCB { + process_state state; + process_t process; +} PCB_t; + +typedef struct process_entry { + int p_id; + PCB_t *PCB; +} process_entry_t; + +typedef struct cleanup_data { + int msgQID; + void *processTable; +} cleanup_data_t;