From 6699115e40c3a8d544a9aa08bd5cb4a826d975da Mon Sep 17 00:00:00 2001
From: sherlock <git@aaditagrawal.com>
Date: Fri, 4 Apr 2025 16:10:41 +0530
Subject: [PATCH] feat: implement EDF and RMS scheduling algorithms

Add a new RTOS scheduling implementation with EDF and RMS algorithms.
Introduce a task structure and create task threads to simulate task
execution. Optimize the Banker's Algorithm code comments for clarity.
These changes enhance the understanding and functionality of the
scheduling mechanisms in the system.
---
 OS/C/Week8/aq1.c           |  68 ++++++++++-------
 OS/C/theory/RTOS/edf-rms.c | 152 +++++++++++++++++++++++++++++++++++++
 2 files changed, 194 insertions(+), 26 deletions(-)
 create mode 100644 OS/C/theory/RTOS/edf-rms.c

diff --git a/OS/C/Week8/aq1.c b/OS/C/Week8/aq1.c
index 8b4318b..0bb16df 100644
--- a/OS/C/Week8/aq1.c
+++ b/OS/C/Week8/aq1.c
@@ -1,10 +1,11 @@
+{{REWRITTEN_CODE}}
 #include <stdio.h>
 
-// C program for Banker's Algorithm (Safety & Resource Request)
+// C program for Banker's Algorithm (Safety & Resource Request Loop)
 // Optimized for minimal code size (e.g., for writing on paper)
 
 int main() {
-    int p, r, i, j, k, pid, req_pid = -1; // p=procs, r=res; req_pid: -1=initial, >=0 processing req
+    int p, r, i, j, k, pid, req_pid = -1; // req_pid: -1=initial/between reqs, >=0 processing req
     printf("P R:"); scanf("%d%d", &p, &r); // Input num processes and resources
     int av[r], max[p][r], al[p][r], nd[p][r], req[r]; // av=avail, al=alloc, nd=need
     int w[r], fin[p], seq[p]; // w=work, fin=finish, seq=safe sequence
@@ -40,38 +41,53 @@ S:; // Safety Check Algorithm Label
 
     // --- End Safety Check ---
 
-    // Handle result based on phase (initial check or request check)
-    if(req_pid == -1) { // Phase 1: Initial State Check
-        if(safe) {
-            printf("SAFE. Seq:"); for(i=0; i<p; i++) printf(" P%d", seq[i]); puts("");
-        } else { puts("UNSAFE"); goto end; } // If unsafe initially, exit
-
-        // Phase 2: Resource Request
-        printf("PID Req:"); scanf("%d", &pid); req_pid = pid; // Get requesting proc ID
-        printf("Req:"); for(j=0; j<r; j++) scanf("%d", &req[j]); // Get request vector
-
-        // Check 1: Request <= Need
-        for(j=0; j<r; j++) if(req[j] > nd[pid][j]) { puts("Err:Req>Need"); goto end; }
-        // Check 2: Request <= Available
-        for(j=0; j<r; j++) if(req[j] > av[j]) { puts("Wait:Req>Avail"); goto end; }
-
-        // Tentatively allocate resources
-        for(j=0; j<r; j++) { av[j]-=req[j]; al[pid][j]+=req[j]; nd[pid][j]-=req[j]; }
-        puts("Checking req safety...");
-        goto S; // Re-run safety check on the new state
-
-    } else { // Phase 3: Post-Request Safety Check Result
-        if(safe) { // Request is granted if new state is safe
+    // --- Post-Safety Check Decision Logic ---
+    if (req_pid != -1) { // Phase 3: Result of a specific request check
+        if (safe) { // Request granted
              printf("Req OK. Seq:"); for(i=0; i<p; i++) printf(" P%d", seq[i]); puts("");
-        } else { // Request denied if new state is unsafe
+             // State remains modified (available, alloc, need updated)
+        } else { // Request denied
             puts("Req DENIED (unsafe)");
             // Rollback state to before tentative allocation
             pid = req_pid; // Restore pid for rollback
             for(j=0; j<r; j++) { av[j]+=req[j]; al[pid][j]-=req[j]; nd[pid][j]+=req[j]; }
         }
-         // No further action needed after handling the single request
+        req_pid = -1; // Reset for next request cycle
+        goto R; // Go ask for the next request or exit
+    } else { // Phase 1: Result of the initial state check
+        if (safe) {
+            printf("SAFE. Seq:"); for(i=0; i<p; i++) printf(" P%d", seq[i]); puts("");
+            // Initial state is safe, proceed to handle requests
+        } else {
+            puts("UNSAFE"); // Initial state unsafe, cannot proceed
+            goto end;
+        }
     }
 
+R:; // Phase 2: Resource Request Loop Label
+    printf("PID Req (-1 to exit):"); scanf("%d", &pid);
+    if (pid < 0) goto end; // Exit condition
+    // Basic check if PID is valid, can add pid >= p check if needed
+    if (pid >= p) { puts("Invalid PID."); goto R;}
+
+    printf("Req:"); for(j=0; j<r; j++) scanf("%d", &req[j]); // Get request vector
+
+    // Check 1: Request <= Need
+    int check_fail = 0;
+    for(j=0; j<r; j++) if(req[j] > nd[pid][j]) { check_fail = 1; break; }
+    if (check_fail) { puts("Err:Req>Need"); goto R; } // Ask for next request
+
+    // Check 2: Request <= Available
+    check_fail = 0;
+    for(j=0; j<r; j++) if(req[j] > av[j]) { check_fail = 1; break; }
+    if (check_fail) { puts("Wait:Req>Avail"); goto R; } // Ask for next request
+
+    // Tentatively allocate resources
+    for(j=0; j<r; j++) { av[j]-=req[j]; al[pid][j]+=req[j]; nd[pid][j]-=req[j]; }
+    req_pid = pid; // Set flag indicating we are checking this specific request
+    puts("Checking req safety...");
+    goto S; // Re-run safety check on the new tentative state
+
 end: return 0; // End of program
 }
 
diff --git a/OS/C/theory/RTOS/edf-rms.c b/OS/C/theory/RTOS/edf-rms.c
new file mode 100644
index 0000000..9a44183
--- /dev/null
+++ b/OS/C/theory/RTOS/edf-rms.c
@@ -0,0 +1,152 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <semaphore.h>
+
+// Define task structure
+typedef struct {
+    int id;
+    int period;
+    int deadline;
+    int execution_time;
+    void (*task_function)(void);
+    int remaining_time;
+} task_t;
+
+// Define global variables
+task_t tasks[3]; // Example with 3 tasks
+int num_tasks = 3;
+pthread_t task_threads[3];
+sem_t scheduler_sem;
+int current_time = 0;
+
+// Task functions (example)
+void task1_function() {
+    printf("Task 1 executing at time %d\n", current_time);
+    usleep(tasks[0].execution_time * 1000); // Simulate execution time
+}
+
+void task2_function() {
+    printf("Task 2 executing at time %d\n", current_time);
+    usleep(tasks[1].execution_time * 1000); // Simulate execution time
+}
+
+void task3_function() {
+    printf("Task 3 executing at time %d\n", current_time);
+    usleep(tasks[2].execution_time * 1000); // Simulate execution time
+}
+
+// EDF Scheduler
+int edf_scheduler() {
+    int earliest_deadline = 100000; // Initialize with a large value
+    int earliest_task_index = -1;
+
+    for (int i = 0; i < num_tasks; i++) {
+        if (tasks[i].remaining_time > 0 && tasks[i].deadline < earliest_deadline) {
+            earliest_deadline = tasks[i].deadline;
+            earliest_task_index = i;
+        }
+    }
+
+    return earliest_task_index;
+}
+
+// Rate Monotonic Scheduler (RMS) - Simplified for Demonstration
+int rms_scheduler() {
+    int shortest_period = 100000; // Initialize with a large value
+    int shortest_period_task_index = -1;
+
+    for (int i = 0; i < num_tasks; i++) {
+        if (tasks[i].remaining_time > 0 && tasks[i].period < shortest_period) {
+            shortest_period = tasks[i].period;
+            shortest_period_task_index = i;
+        }
+    }
+
+    return shortest_period_task_index;
+}
+
+
+// Task thread function
+void *task_thread(void *arg) {
+    task_t *task = (task_t *)arg;
+
+    while (1) {
+        sem_wait(&scheduler_sem); // Wait for scheduler to release
+
+        if (task->remaining_time > 0) {
+            task->task_function();
+            task->remaining_time -= task->execution_time;
+
+            if (task->remaining_time <= 0) {
+                printf("Task %d completed at time %d\n", task->id, current_time);
+            }
+        }
+
+    }
+    pthread_exit(NULL);
+}
+
+int main() {
+    // Initialize tasks (EDF Example)
+    tasks[0].id = 1;
+    tasks[0].period = 50;
+    tasks[0].deadline = 50;
+    tasks[0].execution_time = 10;
+    tasks[0].task_function = task1_function;
+    tasks[0].remaining_time = tasks[0].execution_time;
+
+    tasks[1].id = 2;
+    tasks[1].period = 100;
+    tasks[1].deadline = 100;
+    tasks[1].execution_time = 15;
+    tasks[1].task_function = task2_function;
+    tasks[1].remaining_time = tasks[1].execution_time;
+
+    tasks[2].id = 3;
+    tasks[2].period = 200;
+    tasks[2].deadline = 200;
+    tasks[2].execution_time = 20;
+    tasks[2].task_function = task3_function;
+    tasks[2].remaining_time = tasks[2].execution_time;
+
+    // Initialize semaphore
+    sem_init(&scheduler_sem, 0, 0);
+
+    // Create task threads
+    for (int i = 0; i < num_tasks; i++) {
+        pthread_create(&task_threads[i], NULL, task_thread, &tasks[i]);
+    }
+
+    // RTOS Scheduler Loop
+    for (current_time = 0; current_time < 500; current_time++) {
+        // Choose scheduling algorithm (EDF or RMS)
+        int next_task_index = edf_scheduler();  // Use EDF
+        //int next_task_index = rms_scheduler(); // Or Use RMS
+
+        if (next_task_index != -1) {
+            sem_post(&scheduler_sem); // Release the semaphore to the selected task
+        }
+
+        usleep(1000); // Simulate 1ms time slice
+
+        // Update deadlines for EDF scheduler
+        for (int i = 0; i < num_tasks; i++) {
+            if (current_time % tasks[i].period == 0) {
+                tasks[i].deadline = current_time + tasks[i].period;
+                tasks[i].remaining_time = tasks[i].execution_time;
+                printf("Task %d released at time %d, deadline = %d\n", tasks[i].id, current_time, tasks[i].deadline);
+
+            }
+        }
+    }
+
+    // Clean up
+    for (int i = 0; i < num_tasks; i++) {
+        pthread_cancel(task_threads[i]);
+    }
+    sem_destroy(&scheduler_sem);
+
+    return 0;
+}