added optimised OS codes
This commit is contained in:
parent
fbcc758f43
commit
86ff7c0f35
9 changed files with 723 additions and 0 deletions
BIN
OS/C/Week9/aq1
Executable file
BIN
OS/C/Week9/aq1
Executable file
Binary file not shown.
125
OS/C/Week9/aq1.c
Normal file
125
OS/C/Week9/aq1.c
Normal file
|
@ -0,0 +1,125 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Dynamic Storage Allocation: First Fit & Best Fit
|
||||
// Optimized for minimal code size (e.g., for writing on paper)
|
||||
|
||||
// Block structure: s=start, z=size, p=process_id (0 if free)
|
||||
struct B {int s, z, p;} *b;
|
||||
int nb = 0, cap = 4, mem_sz; // num_blocks, capacity, total_memory_size
|
||||
|
||||
// insb: insert block at index idx, maintain order by start address 's'
|
||||
void insb(int idx, int s, int z, int p) {
|
||||
if (nb >= cap) {
|
||||
cap *= 2;
|
||||
b = realloc(b, cap * sizeof(struct B));
|
||||
// Note: Real-world code checks realloc failure. Skipped for brevity.
|
||||
}
|
||||
for (int k = nb; k > idx; k--) b[k] = b[k-1]; // Shift right
|
||||
b[idx] = (struct B){s, z, p};
|
||||
nb++;
|
||||
}
|
||||
|
||||
// rmb: remove block at index idx
|
||||
void rmb(int idx) {
|
||||
for (int k = idx; k < nb - 1; k++) b[k] = b[k+1]; // Shift left
|
||||
nb--;
|
||||
}
|
||||
|
||||
// pb: print current blocks state
|
||||
void pb() {
|
||||
printf("Mem:[");
|
||||
// Print each block: start:size! (allocated) or start:size (free)
|
||||
for(int i=0; i<nb; i++) printf(" %d:%d%s", b[i].s, b[i].z, b[i].p ? "!" : "");
|
||||
printf(" ]\n");
|
||||
}
|
||||
|
||||
// ff: First Fit allocation
|
||||
void ff(int pid, int sz) {
|
||||
int f = -1; // found index
|
||||
for (int i = 0; i < nb; i++) { // Find first free block large enough
|
||||
if (!b[i].p && b[i].z >= sz) { f = i; break; }
|
||||
}
|
||||
if (f != -1) { // Block found
|
||||
if (b[f].z > sz) { // Need to split block
|
||||
// Insert new free block for the remainder after the allocated part
|
||||
insb(f + 1, b[f].s + sz, b[f].z - sz, 0);
|
||||
b[f].z = sz; // Adjust size of the now-allocated block
|
||||
}
|
||||
b[f].p = pid; // Mark block as allocated to pid
|
||||
printf("FF OK P%d->%d@%d\n", pid, sz, b[f].s);
|
||||
} else printf("FF Fail P%d(%d)\n", pid, sz); // Allocation failed
|
||||
pb(); // Show memory state
|
||||
}
|
||||
|
||||
// bf: Best Fit allocation
|
||||
void bf(int pid, int sz) {
|
||||
int bi = -1, min_z = mem_sz + 1; // best_index, min_suitable_size
|
||||
for (int i = 0; i < nb; i++) { // Find smallest free block large enough
|
||||
if (!b[i].p && b[i].z >= sz && b[i].z < min_z) {
|
||||
min_z = b[i].z; // Update best size found
|
||||
bi = i; // Update best index found
|
||||
}
|
||||
}
|
||||
if (bi != -1) { // Best fit block found
|
||||
if (b[bi].z > sz) { // Need to split block
|
||||
// Insert new free block for the remainder
|
||||
insb(bi + 1, b[bi].s + sz, b[bi].z - sz, 0);
|
||||
b[bi].z = sz; // Adjust size of the allocated block
|
||||
}
|
||||
b[bi].p = pid; // Mark block allocated
|
||||
printf("BF OK P%d->%d@%d\n", pid, sz, b[bi].s);
|
||||
} else printf("BF Fail P%d(%d)\n", pid, sz); // Allocation failed
|
||||
pb(); // Show memory state
|
||||
}
|
||||
|
||||
// de: Deallocate block associated with pid
|
||||
void de(int pid) {
|
||||
int f = -1; // found index
|
||||
for (int i = 0; i < nb; i++) if (b[i].p == pid) { f = i; break; } // Find block by pid
|
||||
|
||||
if (f != -1) { // Block found
|
||||
printf("De OK P%d@%d(%d)\n", pid, b[f].s, b[f].z);
|
||||
b[f].p = 0; // Mark block as free
|
||||
|
||||
// Try merging with the *next* block if it exists and is free
|
||||
if (f + 1 < nb && !b[f+1].p) {
|
||||
b[f].z += b[f+1].z; // Absorb next block's size
|
||||
rmb(f + 1); // Remove the next block entry
|
||||
}
|
||||
// Try merging with the *previous* block if it exists and is free
|
||||
if (f > 0 && !b[f-1].p) {
|
||||
b[f-1].z += b[f].z; // Add current block's size to previous
|
||||
rmb(f); // Remove the current block entry (now merged)
|
||||
// f = f-1; // If index 'f' were needed after merge, adjust it
|
||||
}
|
||||
pb(); // Show memory state
|
||||
} else printf("De Fail P%d\n", pid); // Deallocation failed (pid not found)
|
||||
}
|
||||
|
||||
// Main driver loop
|
||||
int main() {
|
||||
printf("MemSz:"); scanf("%d", &mem_sz); // Get total memory size
|
||||
b = malloc(cap * sizeof(struct B)); // Allocate initial block array
|
||||
if (!b) return 1; // Handle malloc failure
|
||||
b[0] = (struct B){0, mem_sz, 0}; // Create the first block (all memory, free)
|
||||
nb = 1;
|
||||
pb(); // Show initial state
|
||||
|
||||
int choice, pid, sz;
|
||||
printf("1:FF 2:BF 3:Dealloc 0:Exit\n");
|
||||
// Loop until user enters 0
|
||||
while(scanf("%d", &choice) == 1 && choice) {
|
||||
if (choice == 1 || choice == 2) { // Allocate request
|
||||
printf("PID Sz:"); scanf("%d%d", &pid, &sz);
|
||||
if (choice == 1) ff(pid, sz); else bf(pid, sz);
|
||||
} else if (choice == 3) { // Deallocate request
|
||||
printf("PID:"); scanf("%d", &pid);
|
||||
de(pid);
|
||||
} else printf("?\n"); // Invalid choice
|
||||
printf("1:FF 2:BF 3:Dealloc 0:Exit\n"); // Prompt again
|
||||
}
|
||||
|
||||
free(b); // Free the block array memory
|
||||
return 0;
|
||||
}
|
272
OS/C/Week9/q1.c
Normal file
272
OS/C/Week9/q1.c
Normal file
|
@ -0,0 +1,272 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h> // For INT_MAX
|
||||
|
||||
// Structure for a memory block
|
||||
typedef struct Block {
|
||||
int id; // Block ID (optional, can use address for uniqueness)
|
||||
int size; // Size of the block
|
||||
int allocated; // 0 if free, 1 if allocated
|
||||
int process_id; // ID of process allocated to this block (-1 if free)
|
||||
struct Block *next; // Pointer to the next block in the list
|
||||
struct Block *prev; // Pointer to the previous block in the list (for potential merging)
|
||||
} Block;
|
||||
|
||||
// Global head of the memory block linked list
|
||||
Block *memory_head = NULL;
|
||||
|
||||
// Function to create a new block node
|
||||
Block* create_block(int id, int size, int allocated, int process_id) {
|
||||
Block *new_block = (Block*)malloc(sizeof(Block));
|
||||
if (!new_block) {
|
||||
perror("Failed to allocate memory for block");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
new_block->id = id;
|
||||
new_block->size = size;
|
||||
new_block->allocated = allocated;
|
||||
new_block->process_id = process_id;
|
||||
new_block->next = NULL;
|
||||
new_block->prev = NULL;
|
||||
return new_block;
|
||||
}
|
||||
|
||||
// Function to initialize the memory list with one large free block
|
||||
void initialize_memory(int total_size) {
|
||||
if (memory_head != NULL) {
|
||||
// Simple cleanup for re-initialization (more robust needed for general use)
|
||||
Block *current = memory_head;
|
||||
Block *next_node;
|
||||
while(current != NULL) {
|
||||
next_node = current->next;
|
||||
free(current);
|
||||
current = next_node;
|
||||
}
|
||||
memory_head = NULL; // Reset head
|
||||
}
|
||||
memory_head = create_block(0, total_size, 0, -1); // ID 0, size, free, no process
|
||||
}
|
||||
|
||||
// Function to display the current state of memory blocks
|
||||
void display_memory() {
|
||||
Block *current = memory_head;
|
||||
printf("Memory Blocks:\n");
|
||||
printf("----------------------------------------------------\n");
|
||||
printf("| ID | Size | Status | Process ID |\n");
|
||||
printf("----------------------------------------------------\n");
|
||||
while (current != NULL) {
|
||||
printf("| %-2d | %-9d | %-9s | %-10d |\n",
|
||||
current->id,
|
||||
current->size,
|
||||
current->allocated ? "Allocated" : "Free",
|
||||
current->allocated ? current->process_id : -1);
|
||||
current = current->next;
|
||||
}
|
||||
printf("----------------------------------------------------\n\n");
|
||||
}
|
||||
|
||||
// Function to allocate memory using First Fit strategy
|
||||
int allocate_first_fit(int process_id, int required_size) {
|
||||
Block *current = memory_head;
|
||||
Block *best_block = NULL;
|
||||
|
||||
// Find the first free block that is large enough
|
||||
while (current != NULL) {
|
||||
if (!current->allocated && current->size >= required_size) {
|
||||
best_block = current;
|
||||
break; // First fit found
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
// If a suitable block is found
|
||||
if (best_block != NULL) {
|
||||
// Check if splitting is necessary (and worthwhile, e.g., remaining > 0)
|
||||
if (best_block->size > required_size) {
|
||||
// Create a new block for the remaining free space
|
||||
int remaining_size = best_block->size - required_size;
|
||||
// For simplicity, assigning next available ID - needs better management in real system
|
||||
int new_block_id = best_block->id + 1; // simplistic ID assignment
|
||||
Block *new_free_block = create_block(new_block_id, remaining_size, 0, -1);
|
||||
|
||||
// Update the allocated block
|
||||
best_block->size = required_size;
|
||||
best_block->allocated = 1;
|
||||
best_block->process_id = process_id;
|
||||
|
||||
// Insert the new free block into the list
|
||||
new_free_block->next = best_block->next;
|
||||
new_free_block->prev = best_block;
|
||||
if (best_block->next != NULL) {
|
||||
best_block->next->prev = new_free_block;
|
||||
}
|
||||
best_block->next = new_free_block;
|
||||
|
||||
// Renumber subsequent block IDs (basic approach)
|
||||
Block* temp = new_free_block->next;
|
||||
int current_id = new_block_id + 1;
|
||||
while (temp != NULL) {
|
||||
temp->id = current_id++;
|
||||
temp = temp->next;
|
||||
}
|
||||
|
||||
} else { // Exact fit or minimal leftover space (allocate the whole block)
|
||||
best_block->allocated = 1;
|
||||
best_block->process_id = process_id;
|
||||
}
|
||||
printf("Process %d allocated %d units using First Fit in Block %d.\n", process_id, required_size, best_block->id);
|
||||
return 1; // Allocation successful
|
||||
} else {
|
||||
printf("Process %d (size %d) could not be allocated using First Fit.\n", process_id, required_size);
|
||||
return 0; // Allocation failed
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Function to allocate memory using Best Fit strategy
|
||||
int allocate_best_fit(int process_id, int required_size) {
|
||||
Block *current = memory_head;
|
||||
Block *best_block = NULL;
|
||||
int min_waste = INT_MAX;
|
||||
|
||||
// Find the smallest free block that is large enough
|
||||
while (current != NULL) {
|
||||
if (!current->allocated && current->size >= required_size) {
|
||||
int waste = current->size - required_size;
|
||||
if (waste < min_waste) {
|
||||
min_waste = waste;
|
||||
best_block = current;
|
||||
}
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
// If a suitable block is found
|
||||
if (best_block != NULL) {
|
||||
// Check if splitting is necessary (and worthwhile, e.g., remaining > 0)
|
||||
if (best_block->size > required_size) {
|
||||
// Create a new block for the remaining free space
|
||||
int remaining_size = best_block->size - required_size;
|
||||
int new_block_id = best_block->id + 1; // simplistic ID assignment
|
||||
Block *new_free_block = create_block(new_block_id, remaining_size, 0, -1);
|
||||
|
||||
// Update the allocated block
|
||||
best_block->size = required_size;
|
||||
best_block->allocated = 1;
|
||||
best_block->process_id = process_id;
|
||||
|
||||
// Insert the new free block into the list
|
||||
new_free_block->next = best_block->next;
|
||||
new_free_block->prev = best_block;
|
||||
if (best_block->next != NULL) {
|
||||
best_block->next->prev = new_free_block;
|
||||
}
|
||||
best_block->next = new_free_block;
|
||||
|
||||
// Renumber subsequent block IDs (basic approach)
|
||||
Block* temp = new_free_block->next;
|
||||
int current_id = new_block_id + 1;
|
||||
while (temp != NULL) {
|
||||
temp->id = current_id++;
|
||||
temp = temp->next;
|
||||
}
|
||||
|
||||
} else { // Exact fit (allocate the whole block)
|
||||
best_block->allocated = 1;
|
||||
best_block->process_id = process_id;
|
||||
}
|
||||
printf("Process %d allocated %d units using Best Fit in Block %d.\n", process_id, required_size, best_block->id);
|
||||
return 1; // Allocation successful
|
||||
} else {
|
||||
printf("Process %d (size %d) could not be allocated using Best Fit.\n", process_id, required_size);
|
||||
return 0; // Allocation failed
|
||||
}
|
||||
}
|
||||
|
||||
// Function to free all allocated memory for the linked list
|
||||
void cleanup_memory() {
|
||||
Block *current = memory_head;
|
||||
Block *next_node;
|
||||
while (current != NULL) {
|
||||
next_node = current->next;
|
||||
free(current);
|
||||
current = next_node;
|
||||
}
|
||||
memory_head = NULL;
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
int total_memory;
|
||||
int num_processes;
|
||||
int *process_sizes = NULL; // Dynamically allocated array for process sizes
|
||||
int i;
|
||||
|
||||
// --- Input ---
|
||||
printf("Enter the total size of memory: ");
|
||||
scanf("%d", &total_memory);
|
||||
if (total_memory <= 0) {
|
||||
printf("Invalid memory size.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Enter the number of processes: ");
|
||||
scanf("%d", &num_processes);
|
||||
if (num_processes <= 0) {
|
||||
printf("Invalid number of processes.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Dynamically allocate array for process sizes
|
||||
process_sizes = (int*)malloc(num_processes * sizeof(int));
|
||||
if (!process_sizes) {
|
||||
perror("Failed to allocate memory for process sizes");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Enter the size required for each process:\n");
|
||||
for (i = 0; i < num_processes; i++) {
|
||||
printf("Process %d size: ", i + 1);
|
||||
scanf("%d", &process_sizes[i]);
|
||||
if (process_sizes[i] <= 0) {
|
||||
printf("Invalid process size. Please enter a positive value.\n");
|
||||
free(process_sizes);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
|
||||
// --- First Fit Simulation ---
|
||||
printf("--- First Fit Allocation ---\n");
|
||||
initialize_memory(total_memory);
|
||||
printf("Initial Memory State:\n");
|
||||
display_memory();
|
||||
|
||||
for (i = 0; i < num_processes; i++) {
|
||||
allocate_first_fit(i + 1, process_sizes[i]); // Process IDs starting from 1
|
||||
display_memory(); // Show state after each allocation attempt
|
||||
}
|
||||
printf("Final Memory State after First Fit:\n");
|
||||
display_memory();
|
||||
|
||||
|
||||
// --- Best Fit Simulation ---
|
||||
printf("\n--- Best Fit Allocation ---\n");
|
||||
initialize_memory(total_memory); // Re-initialize memory for a fresh start
|
||||
printf("Initial Memory State:\n");
|
||||
display_memory();
|
||||
|
||||
for (i = 0; i < num_processes; i++) {
|
||||
allocate_best_fit(i + 1, process_sizes[i]); // Process IDs starting from 1
|
||||
display_memory(); // Show state after each allocation attempt
|
||||
}
|
||||
printf("Final Memory State after Best Fit:\n");
|
||||
display_memory();
|
||||
|
||||
// --- Cleanup ---
|
||||
free(process_sizes); // Free the dynamically allocated process sizes array
|
||||
cleanup_memory(); // Free the memory blocks linked list
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue