/** * @file * @brief * [Non-Preemptive Priority * Scheduling](https://en.wikipedia.org/wiki/Scheduling_(computing)) * is a scheduling algorithm that selects the tasks to execute based on * priority. * * @details * In this algorithm, processes are executed according to their * priority. The process with the highest priority is to be executed first and * so on. In this algorithm, a variable is maintained known as the time quantum. * The length of the time quantum is decided by the user. The process which is * being executed is interrupted after the expiration of the time quantum and * the next process with the highest priority is executed. This cycle of * interrupting the process after every time quantum and resuming the next * process with the highest priority continues until all the processes have * been executed. * @author [Aryan Raj](https://github.com/aryaraj132) */ #include /// for assert #include /// for boolean data type #include /// for IO operations (`printf`) #include /// for memory allocation eg: `malloc`, `realloc`, `free`, `exit` /** * @brief Structure to represent a process */ typedef struct node { int ID; ///< ID of the process node int AT; ///< Arrival Time of the process node int BT; ///< Burst Time of the process node int priority; ///< Priority of the process node int CT; ///< Completion Time of the process node int WT; ///< Waiting Time of the process node int TAT; ///< Turn Around Time of the process node struct node *next; ///< pointer to the node } node; /** * @brief To insert a new process in the queue * @param root pointer to the head of the queue * @param id process ID * @param at arrival time * @param bt burst time * @param prior priority of the process * @returns void */ void insert(node **root, int id, int at, int bt, int prior) { // create a new node and initialize it node *new = (node *)malloc(sizeof(node)); node *ptr = *root; new->ID = id; new->AT = at; new->BT = bt; new->priority = prior; new->next = NULL; new->CT = 0; new->WT = 0; new->TAT = 0; // if the root is null, make the new node the root if (*root == NULL) { *root = new; return; } // else traverse to the end of the queue and insert the new node there while (ptr->next != NULL) { ptr = ptr->next; } ptr->next = new; return; } /* * @brief To delete a process from the queue * @param root pointer to the head of the queue * @param id process ID * @returns void */ void delete(node **root, int id) { node *ptr = *root, *prev; // if the root is null, return if (ptr == NULL) { return; } // if the root is the process to be deleted, make the next node the root if (ptr->ID == id) { *root = ptr->next; free(ptr); return; } // else traverse the queue and delete the process while (ptr != NULL && ptr->ID != id) { prev = ptr; ptr = ptr->next; } if (ptr == NULL) { return; } prev->next = ptr->next; free(ptr); } /** * @brief To show the process queue * @param head pointer to the head of the queue * @returns void */ void show_list(node *head) { printf("Process Priority AT BT CT TAT WT \n"); while (head != NULL) { printf("P%d. %d %d %d %d %d %d \n", head->ID, head->priority, head->AT, head->BT, head->CT, head->TAT, head->WT); head = head->next; } } /** * @brief To length process queue * @param root pointer to the head of the queue * @returns int total length of the queue */ int l_length(node **root) { int count = 0; node *ptr = *root; while (ptr != NULL) { count++; ptr = ptr->next; } return count; } /** * @brief To update the completion time, turn around time and waiting time of * the processes * @param root pointer to the head of the queue * @param id process ID * @param ct current time * @param wt waiting time * @param tat turn around time * @returns void */ void update(node **root, int id, int ct, int wt, int tat) { node *ptr = *root; // If process to be updated is head node if (ptr != NULL && ptr->ID == id) { if (ct != 0) { ptr->CT = ct; } if (wt != 0) { ptr->WT = wt; } if (tat != 0) { ptr->TAT = tat; } return; } // else traverse the queue and update the values while (ptr != NULL && ptr->ID != id) { ptr = ptr->next; } if (ct != 0) { ptr->CT = ct; } if (wt != 0) { ptr->WT = wt; } if (tat != 0) { ptr->TAT = tat; } return; } /** * @brief To compare the priority of two processes based on their arrival time * and priority * @param a pointer to the first process * @param b pointer to the second process * @returns true if the priority of the first process is greater than the * the second process * @returns false if the priority of the first process is NOT greater than the * second process */ bool compare(node *a, node *b) { if (a->AT == b->AT) { return a->priority < b->priority; } else { return a->AT < b->AT; } } /** * @brief To calculate the average completion time of all the processes * @param root pointer to the head of the queue * @returns float average completion time */ float calculate_ct(node **root) { // calculate the total completion time of all the processes node *ptr = *root, *prior, *rpt; int ct = 0, i, time = 0; int n = l_length(root); float avg, sum = 0; node *duproot = NULL; // create a duplicate queue while (ptr != NULL) { insert(&duproot, ptr->ID, ptr->AT, ptr->BT, ptr->priority); ptr = ptr->next; } ptr = duproot; rpt = ptr->next; // sort the queue based on the arrival time and priority while (rpt != NULL) { if (!compare(ptr, rpt)) { ptr = rpt; } rpt = rpt->next; } // ptr is the process to be executed first. ct = ptr->AT + ptr->BT; time = ct; sum += ct; // update the completion time, turn around time and waiting time of the // process update(root, ptr->ID, ct, 0, 0); delete (&duproot, ptr->ID); // repeat the process until all the processes are executed for (i = 0; i < n - 1; i++) { ptr = duproot; while (ptr != NULL && ptr->AT > time) { ptr = ptr->next; } rpt = ptr->next; while (rpt != NULL) { if (rpt->AT <= time) { if (rpt->priority < ptr->priority) { ptr = rpt; } } rpt = rpt->next; } ct += ptr->BT; time += ptr->BT; sum += ct; update(root, ptr->ID, ct, 0, 0); delete (&duproot, ptr->ID); } avg = sum / n; return avg; } /** * @brief To calculate the average turn around time of all the processes * @param root pointer to the head of the queue * @returns float average turn around time */ float calculate_tat(node **root) { float avg, sum = 0; int n = l_length(root); node *ptr = *root; // calculate the completion time if not already calculated if (ptr->CT == 0) { calculate_ct(root); } // calculate the total turn around time of all the processes while (ptr != NULL) { ptr->TAT = ptr->CT - ptr->AT; sum += ptr->TAT; ptr = ptr->next; } avg = sum / n; return avg; } /** * @brief To calculate the average waiting time of all the processes * @param root pointer to the head of the queue * @returns float average waiting time */ float calculate_wt(node **root) { float avg, sum = 0; int n = l_length(root); node *ptr = *root; // calculate the completion if not already calculated if (ptr->CT == 0) { calculate_ct(root); } // calculate the total waiting time of all the processes while (ptr != NULL) { ptr->WT = (ptr->TAT - ptr->BT); sum += ptr->WT; ptr = ptr->next; } avg = sum / n; return avg; } /** * @brief Self-test implementations * @returns void */ static void test() { // Entered processes // printf("ID Priority Arrival Time Burst Time \n"); // printf("1 0 5 1 \n"); // printf("2 1 4 2 \n"); // printf("3 2 3 3 \n"); // printf("4 3 2 4 \n"); // printf("5 4 1 5 \n"); node *root = NULL; insert(&root, 1, 0, 5, 1); insert(&root, 2, 1, 4, 2); insert(&root, 3, 2, 3, 3); insert(&root, 4, 3, 2, 4); insert(&root, 5, 4, 1, 5); float avgCT = calculate_ct(&root); float avgTAT = calculate_tat(&root); float avgWT = calculate_wt(&root); assert(avgCT == 11); assert(avgTAT == 9); assert(avgWT == 6); printf("[+] All tests have successfully passed!\n"); // printf("Average Completion Time is : %f \n", calculate_ct(&root)); // printf("Average Turn Around Time is : %f \n", calculate_tat(&root)); // printf("Average Waiting Time is : %f \n", calculate_wt(&root)); } /** * @brief Main function * @returns 0 on exit */ int main() { test(); // run self-test implementations return 0; }