0% found this document useful (0 votes)
5 views

Lab Report

The document covers the implementation of process creation, termination, thread management, inter-process communication, and various CPU scheduling algorithms. It provides objectives, theoretical background, source code examples, and results for each topic, demonstrating the understanding of these concepts through practical programming exercises. Key techniques discussed include process management using system calls, thread synchronization, IPC methods, and scheduling algorithms like FCFS, SJF, SRTF, Round Robin, and Priority Scheduling.

Uploaded by

007aashishregmi
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views

Lab Report

The document covers the implementation of process creation, termination, thread management, inter-process communication, and various CPU scheduling algorithms. It provides objectives, theoretical background, source code examples, and results for each topic, demonstrating the understanding of these concepts through practical programming exercises. Key techniques discussed include process management using system calls, thread synchronization, IPC methods, and scheduling algorithms like FCFS, SJF, SRTF, Round Robin, and Priority Scheduling.

Uploaded by

007aashishregmi
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 106

TITLE: IMPLEMENTATION OF PROCESS CREATION AND TERMINATION.

OBJECTIVE:
i) To learn about creating, controlling and terminating processes in the program.

THEORY:
Processes are created by a parent process using system calls like fork( ), forming a parent-
child relationship. The child process inherits certain attributes from its parent, such as open
files and execution context, and may execute independently or load a new program using
system calls like exec( ).
All processes are organized in a hierarchical tree structure within the system. A process
terminates either voluntarily, using calls like exit( ), or involuntarily due to errors or external
signals such as kill. After termination, the operating system cleans up the resources allocated
to the process, and the parent process is notified of the termination through status codes or
signals.

SOURCE CODE:
#include <stdio.h>
int main()
{
int a;
a = 4 + 5;
printf("The result is:%d",a);
}

OUTPUT:

RESULT AND CONCLUSION:


In this lab, we demonstrated our comprehension of process creation & termination by crafting
a program with single process through the implementation of various C programming library
files.
TITLE: IMPLEMENTATION OF THREAD CREATION AND TERMINATION.

OBJECTIVE:
i) To learn about creating and terminating threads for efficient multitasking and
resource management.

THEORY:
Thread creation and termination are fundamental concepts in multithreaded programming.
Threads are lightweight processes that share the same memory space, enabling efficient
multitasking within an application. Threads can be created using system calls or library
functions, such as pthread_create() in C or Thread in Java.
During creation, each thread is assigned a unique identifier and executes a specific task or
function. A thread terminates either after completing its assigned task or through explicit
termination calls like pthread_exit() or thread.interrupt().
Proper synchronization mechanisms, such as mutexes or semaphores, are essential to manage
shared resources and avoid race conditions. Efficient thread creation and termination enhance
application performance and resource utilization.

SOURCE CODE:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// Thread function
void* thread_function(void* arg)
{
int thread_id = *((int*)arg);
printf("Thread %d: Starting\n", thread_id);
sleep(2); // Simulate some work
printf("Thread %d: Ending\n", thread_id);
pthread_exit(NULL); // Exit the thread
}
int main()
{
pthread_t threads[3];
int thread_ids[3];
int i;
// Creating threads
for (i = 0; i < 3; i++)
{
thread_ids[i] = i + 1;
if (pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]) != 0)
{
perror("Failed to create thread");
exit(EXIT_FAILURE);
}
printf("Main: Created thread %d\n", thread_ids[i]);
}
// Joining threads (wait for them to finish)
for (i = 0; i < 3; i++)
{
if (pthread_join(threads[i], NULL) != 0)
{
perror("Failed to join thread");
exit(EXIT_FAILURE);
}
printf("Main: Joined thread %d\n", thread_ids[i]);
}
printf("Main: All threads finished. Exiting.\n");
return 0;
}
OUTPUT:

RESULT AND CONCLUSION:


In this lab, we demonstrated our comprehension of thread creation & termination by crafting
a program through the implementation of various C programming library files.
TITLE: IMPLEMENTATION OF INTER-PROCESS COMMUNICATION TECHNIQUE.

OBJECTIVE:
i) To learn about understanding inter-process communication (IPC) techniques for
efficient data exchange and synchronization between processes.

THEORY:
Inter-process communication (IPC) enables processes to share data and coordinate their
actions. IPC techniques include pipes, message queues, shared memory, and sockets, each
suited for specific use cases. Pipes provide a unidirectional communication channel, while
message queues allow asynchronous message exchange.
Shared memory facilitates direct memory access between processes for faster data sharing,
but it requires proper synchronization. Sockets enable communication between processes
over a network, supporting distributed systems. Semaphores and mutexes are often used
alongside IPC methods to prevent race conditions and ensure safe resource access.
IPC mechanisms are crucial for parallel processing and resource sharing in modern systems.
Proper implementation ensures data integrity, synchronization, and efficient communication
between processes.

SOURCE CODE:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
int main()
{
HANDLE hRead, hWrite;
SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL,
TRUE};
char write_msg[] = "Hello from parent!";
char read_msg[100];
DWORD bytes_written, bytes_read;

// Create a pipe
if (!CreatePipe(&hRead, &hWrite, &sa, 0))
{
fprintf(stderr, "Pipe creation failed.\n");
return 1;
}

// Create a child process


PROCESS_INFORMATION pi;
STARTUPINFO si = {sizeof(STARTUPINFO)};
si.hStdOutput = hWrite; // Redirect child output to the pipe
si.hStdError = hWrite; // Redirect child errors to the pipe
si.dwFlags |= STARTF_USESTDHANDLES;

if (!CreateProcess(NULL, _T("child_process.exe"), NULL, NULL, TRUE, 0, NULL,


NULL, &si, &pi))
{
fprintf(stderr, "Process creation failed.\n");
CloseHandle(hRead);
CloseHandle(hWrite);
return 1;
}
// Parent process writes to the pipe
printf("Parent: Writing message to pipe: \"%s\"\n", write_msg);
if (!WriteFile(hWrite, write_msg, sizeof(write_msg), &bytes_written, NULL))
{
fprintf(stderr, "Write to pipe failed.\n");
}
CloseHandle(hWrite); // Close write end

// Parent reads the response


if (ReadFile(hRead, read_msg, sizeof(read_msg), &bytes_read, NULL))
{
printf("Parent: Read message from pipe: \"%.*s\"\n", bytes_read, read_msg);
}
else
{
fprintf(stderr, "Read from pipe failed.\n");
}
CloseHandle(hRead); // Close read end

// Wait for the child process to finish


WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}

OUTPUT:

RESULT AND CONCLUSION:


In this lab, we demonstrated our comprehension of inter-process communication (IPC)
techniques by crafting a program through the implementation of various C programming
library files.
TITLE: IMPLEMENTATION OF PROCESS SCHEDULING ALGORITHMS.

OBJECTIVE:
i) To learn about analyzing different process scheduling algorithms for optimizing CPU
utilization and system performance.
THEORY:
Process scheduling algorithms determine the order in which processes are executed by the
CPU. Common algorithms include First-Come-First-Serve (FCFS), Shortest Job First (SJF),
Shortest Remaining Time First (SRTF), Round Robin (RR), and Priority Scheduling.
FCFS schedules processes based on their arrival time, leading to potential inefficiencies like
the "convoy effect." SJF schedules processes with the shortest burst time first, minimizing
waiting time but suffering from starvation for longer processes. SRTF is the preemptive
version of SJF which schedules process for one second each based on burst time.
Similarly, Round Robin allocates a fixed time slice to each process, ensuring fairness but
potentially increasing turnaround time. Priority Scheduling executes processes based on
priority levels, which can be preemptive or non-preemptive. Proper implementation of these
algorithms ensures efficient CPU utilization, minimizes waiting and turnaround times, and
improves overall system performance.
First-Come-First-Serve(FCFS) CPU Scheduling:

SOURCE CODE:
#include <stdio.h>
int main()
{
int n, bt[20], wt[20], tat[20], avwt = 0, avtat = 0, i, j;

// Input number of processes


printf("Enter total number of processes (maximum 20): ");
scanf("%d", &n);

// Input burst times for each process


printf("\nEnter Process Burst Time:\n");
for(i = 0; i < n; i++)
{
printf("P[%d]: ", i + 1);
scanf("%d", &bt[i]);
}
// Calculate waiting time for each process
wt[0] = 0; // First process has no waiting time
for(i = 1; i < n; i++)
{
wt[i] = 0;
for(j = 0; j < i; j++)
{
wt[i] += bt[j]; // Add the burst time of previous processes
}
}
// Display the table headers
printf("\nProcess\tBurst Time\tWaiting Time\tTurnaround Time\n");

// Calculate turnaround time and print results


for(i = 0; i < n; i++)
{
tat[i] = bt[i] + wt[i]; // Turnaround Time = Burst Time + Waiting Time
avwt += wt[i]; // Total Waiting Time
avtat += tat[i]; // Total Turnaround Time
printf("P[%d]\t\t%d\t\t%d\t\t%d\n", i + 1, bt[i], wt[i], tat[i]);
}
// Calculate average waiting time and average turnaround time
avwt /= n;
avtat /= n;

// Display average times


printf("\nAverage Waiting Time: %d", avwt);
printf("\nAverage Turnaround Time: %d\n", avtat);
return 0;
}
OUTPUT:

Shortest Job First (SJF) CPU Scheduling:

SOURCE CODE:
#include <stdio.h>
int main()
{
int n, bt[20], p[20], wt[20] = {0}, tat[20], i, j, total_wt = 0, total_tat = 0;

printf("Enter number of processes:");


scanf("%d", &n);
printf("\nEnter Burst Time:\n");
for (i = 0; i < n; i++)
{
printf("P%d: ", i + 1);
scanf("%d", &bt[i]);
p[i] = i + 1;
}
// Sorting burst times and processes
for (i = 0; i < n - 1; i++)
{
for (j = i + 1; j < n; j++)
{
if (bt[i] > bt[j])
{
int temp = bt[i]; bt[i] = bt[j]; bt[j] = temp;

temp = p[i]; p[i] = p[j]; p[j] = temp;


}
}
}
// Calculating waiting and turnaround times
for (i = 1; i < n; i++)
{
wt[i] = wt[i - 1] + bt[i - 1];
}
for (i = 0; i < n; i++)
{
tat[i] = bt[i] + wt[i];
total_wt += wt[i];
total_tat += tat[i];
}
// Printing results
printf("\nProcess\tBurst Time\tWaiting Time\tTurnaround Time\n");
for (i = 0; i < n; i++)
printf("P%d\t%d\t\t%d\t\t%d\n", p[i], bt[i], wt[i], tat[i]);
printf("\nAverage Waiting Time: %.2f", (float)total_wt / n);
printf("\nAverage Turnaround Time: %.2f\n", (float)total_tat / n);
return 0;
}
OUTPUT:

Shortest Remaining Time First (SRTF) CPU Scheduling:

SOURCE CODE:
#include <stdio.h>
#include <limits.h> // Required for INT_MAX
int main()
{
int n, bt[20], rt[20], wt[20] = {0}, tat[20];
int time = 0, completed = 0, smallest;
int i, min_rt; // Declare all variables at the top
float total_wt = 0, total_tat = 0;

printf("Enter number of processes: ");


scanf("%d", &n);
printf("\nEnter Burst Time for each process:\n");
for (i = 0; i < n; i++)
{
printf("P%d: ", i + 1);
scanf("%d", &bt[i]);
rt[i] = bt[i];
}
printf("\nProcess\tBurst Time\tWaiting Time\tTurnaround Time\n");
while (completed < n)
{
smallest = -1;
min_rt = INT_MAX;

// Find the process with the shortest remaining time


for (i = 0; i < n; i++)
{
// Variable `i` is now declared outside
if (rt[i] > 0 && rt[i] < min_rt)
{
min_rt = rt[i];
smallest = i;
}
}
if (smallest == -1)
break;
rt[smallest]--; // Process the selected job
time++;
if (rt[smallest] == 0)
{
// Process completed
completed++;
tat[smallest] = time; // Completion time
wt[smallest] = tat[smallest] - bt[smallest];

total_wt += wt[smallest];
total_tat += tat[smallest];
printf("P%d\t%d\t\t%d\t\t%d\n", smallest + 1, bt[smallest],
wt[smallest], tat[smallest]);
}
}
printf("\nAverage Waiting Time: %.2f", total_wt / n);
printf("\nAverage Turnaround Time: %.2f\n", total_tat / n);
return 0;
}
OUTPUT:
Round Robin CPU Scheduling:

SOURCE CODE:
#include <stdio.h>
int main()
{
int n, tq, bt[20], rt[20], wt[20] = {0}, tat[20] = {0};
int time = 0, completed = 0, i;
float total_wt = 0, total_tat = 0;

printf("Enter number of processes: ");


scanf("%d", &n);
printf("Enter Time Quantum: ");
scanf("%d", &tq);
printf("\nEnter Burst Time for each process:\n");
for (i = 0; i < n; i++)
{
printf("P%d: ", i + 1);
scanf("%d", &bt[i]);
rt[i] = bt[i]; // Initialize remaining times
}
printf("\nProcess\tBurst Time\tWaiting Time\tTurnaround Time\n");
while (completed < n)
{
for (i = 0; i < n; i++)
{
if (rt[i] > 0)
{
int exec_time = (rt[i] > tq) ? tq : rt[i];
time += exec_time;
rt[i] -= exec_time;
if (rt[i] == 0)
{
// Process finished
completed++;
tat[i] = time; // Completion time
wt[i] = tat[i] - bt[i];
total_wt += wt[i];
total_tat += tat[i];
printf("P%d\t%d\t\t%d\t\t%d\n", i + 1, bt[i], wt[i],
tat[i]);
}
}
}
}
printf("\nAverage Waiting Time: %.2f", total_wt / n);
printf("\nAverage Turnaround Time: %.2f\n", total_tat / n);
return 0;
}

OUTPUT:
Priority CPU Scheduling

SOURCE CODE:
#include <stdio.h>
int main()
{
int n, i, j, bt[10], p[10], pr[10], wt[10] = {0}, tat[10] = {0}, temp;
float total_wt = 0, total_tat = 0;

printf("Enter number of processes: ");


scanf("%d", &n);
printf("Enter Burst Time and Priority for each process:\n");
for (i = 0; i < n; i++)
{
printf("P%d Burst Time: ", i + 1);
scanf("%d", &bt[i]);
printf("P%d Priority: ", i + 1);
scanf("%d", &pr[i]);
p[i] = i + 1; // Process number
}
// Sort by priority
for (i = 0; i < n - 1; i++)
{
for (j = i + 1; j < n; j++)
{
if (pr[i] > pr[j])
{
temp = pr[i]; pr[i] = pr[j]; pr[j] = temp;
temp = bt[i]; bt[i] = bt[j]; bt[j] = temp;
temp = p[i]; p[i] = p[j]; p[j] = temp;
}
}
}
// Calculate waiting time and turnaround time
for (i = 1; i < n; i++) wt[i] = wt[i - 1] + bt[i - 1];
for (i = 0; i < n; i++)
{
tat[i] = wt[i] + bt[i];
total_wt += wt[i];
total_tat += tat[i];
}
// Display results
printf("\nProcess\tPriority\tBurst Time\tWaiting Time\tTurnaround Time\n");
for (i = 0; i < n; i++)
printf("P%d\t%d\t\t%d\t\t%d\t\t%d\n", p[i], pr[i], bt[i], wt[i], tat[i]);
printf("\nAverage Waiting Time: %.2f", total_wt / n);
printf("\nAverage Turnaround Time: %.2f\n", total_tat / n);
return 0;
}

OUTPUT:
RESULT AND CONCLUSION:
In this lab, we demonstrated our comprehension of process scheduling algorithms by crafting
a program to calculate average waiting time and average turnaround time of the processes
through the implementation of various C programming library files.
TITLE: IMPLEMENTATION OF BOUNDED BUFFER PROBLEM.

OBJECTIVE:
i) To learn about the Bounded Buffer problem and demonstrate synchronization
between producer and consumer processes using appropriate synchronization
mechanisms.

THEORY:
The Bounded Buffer problem involves managing a fixed-size buffer shared by producer and
consumer processes. The producer generates data and places it into the buffer, while the
consumer retrieves and processes the data. The challenge is to prevent the buffer from being
overfilled or emptied, which can lead to synchronization issues.
Key synchronization mechanisms like semaphores, mutexes, or condition variables are used
to ensure that the producer waits when the buffer is full, and the consumer waits when the
buffer is empty. The solution often involves two semaphores: one for counting the available
spaces and another for counting the number of items in the buffer.
Proper synchronization ensures that both processes can operate concurrently without data
corruption or race conditions, improving the efficiency and reliability of the system such that
the system can run in multitasking environment.

SOURCE CODE:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#define BUFFER_SIZE 5
#define NUM_ITEMS 5

int buffer[BUFFER_SIZE];
int in = 0;
int out = 0;
sem_t empty;
sem_t full;
pthread_mutex_t mutex;

void* producer(void* arg)


{
int i; // Declare 'i' outside the for loop
for (i = 0; i < NUM_ITEMS; i++)
{
sem_wait(&empty);
pthread_mutex_lock(&mutex);
buffer[in] = i;
printf("Producer produced: %d\n", i);
in = (in + 1) % BUFFER_SIZE;
pthread_mutex_unlock(&mutex);
sem_post(&full);
sleep(1); // Simulate time taken to produce an item
}
return NULL;
}
void* consumer(void* arg)
{
int i; // Declare 'i' outside the for loop
for (i = 0; i < NUM_ITEMS; i++)
{
sem_wait(&full);
pthread_mutex_lock(&mutex);
int item = buffer[out];
printf("Consumer consumed: %d\n", item);
out = (out + 1) % BUFFER_SIZE;
pthread_mutex_unlock(&mutex);
sem_post(&empty);
sleep(1); // Simulate time taken to consume an item
}
return NULL;
}
int main()
{
pthread_t prod_thread, cons_thread;
sem_init(&empty, 0, BUFFER_SIZE);
sem_init(&full, 0, 0);
pthread_mutex_init(&mutex, NULL);
pthread_create(&prod_thread, NULL, producer, NULL);
pthread_create(&cons_thread, NULL, consumer, NULL);

pthread_join(prod_thread, NULL);
pthread_join(cons_thread, NULL);
sem_destroy(&empty);
sem_destroy(&full);
pthread_mutex_destroy(&mutex);
return 0;
}

OUTPUT:

RESULT AND CONCLUSION:


In this lab, we demonstrated our comprehension of bounded buffer problem by crafting a
program for Producer-Consumer Problem through the implementation of various C
programming library files.
TITLE: IMPLEMENTATION OF DEADLOCK AVOIDANCE ALGORITM.

OBJECTIVE:
i) To learn about the deadlock avoidance algorithm that prevents deadlock from
occurring by making resource allocation decisions in advance.

THEORY:
Deadlock avoidance algorithms ensure that a system never enters a deadlock state by
carefully controlling resource allocation. One widely used algorithm is the Banker's
Algorithm, which checks the safety of resource allocation before granting a request. It uses
information about maximum resource needs, currently allocated resources, and available
resources to determine if granting a request will lead to a safe or unsafe state.
A safe state is one where all processes can eventually complete without causing a deadlock,
while an unsafe state may lead to deadlock. Deadlock avoidance algorithms require processes
to declare their maximum resource requirements in advance, allowing the system to make
informed decisions.
Although these algorithms can prevent deadlocks, they may reduce system resource
utilization and efficiency. Proper implementation helps maintain system stability by avoiding
deadlocks while ensuring processes can still execute efficiently.

SOURCE CODE:
#include <stdio.h>
#include <stdbool.h>

#define MAX_PROCESSES 10
#define MAX_RESOURCES 10

int n, m; // n = number of processes, m = number of resource types


int available[MAX_RESOURCES], max[MAX_PROCESSES][MAX_RESOURCES],
allocation[MAX_PROCESSES][MAX_RESOURCES], need[MAX_PROCESSES]
[MAX_RESOURCES];

void calculateNeed()
{
int i, j;
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
need[i][j] = max[i][j] - allocation[i][j];
}
}
}
bool isSafe()
{
int work[MAX_RESOURCES], finish[MAX_PROCESSES] = {0};
int safeSequence[MAX_PROCESSES], index = 0;
int i, j, k;

// Initialize work with available resources


for (i = 0; i < m; i++)
{
work[i] = available[i];
}
// Try to find a safe sequence
for (k = 0; k < n; k++)
{
bool found = false;
for (i = 0; i < n; i++)
{
if (finish[i] == 0)
{
// If process i is not finished
for (j = 0; j < m; j++)
{
if (need[i][j] > work[j])
{
break; // Process i cannot proceed
}
}
// If all resources for process i can be allocated
if (j == m)
{
// Allocate resources to process i
for (int y = 0; y < m; y++)
{
// Add allocated resources to work
work[y] += allocation[i][y];
}
// Record the process in safe sequence
safeSequence[index++] = i;
finish[i] = 1; // Mark process as finished
found = true; // Indicate that we found a process
}
}
}
if (!found)
{
// No process could proceed
break; // Exit the loop if no process can proceed
}
}
// Check if all processes finished
for (i = 0; i < n; i++)
{
if (finish[i] == 0)
{
printf("The system is in an unsafe state!\n");
return false;
}
}
// If the system is safe
printf("The system is in a safe state.\nSafe sequence is: ");
for (i = 0; i < index; i++)
{
// Print only the finished processes
printf("P%d ", safeSequence[i]);
}
printf("\n");
return true;
}
int main()
{
printf("Enter the number of processes (max %d): ", MAX_PROCESSES);
scanf("%d", &n);
printf("Enter the number of resource types (max %d): ", MAX_RESOURCES);
scanf("%d", &m);

// Input for available resources


printf("Enter the available resources: \n");
for (int i = 0; i < m; i++)
{
scanf("%d", &available[i]);
}
// Input for maximum resource matrix
printf("Enter the maximum resource matrix (Max): \n");
for (int i = 0; i < n; i++)
{
printf("For process P%d: ", i);
for (int j = 0; j < m; j++)
{
scanf("%d", &max[i][j]);
}
}
// Input for allocation resource matrix
printf("Enter the allocation resource matrix (Allocation): \n");
for (int i = 0; i < n; i++)
{
printf("For process P%d: ", i);
for (int j = 0; j < m; j++)
{
scanf("%d", &allocation[i][j]);
}
}
// Calculate need and check if the system is in a safe state
calculateNeed();
isSafe();
return 0;
}
OUTPUT:

RESULT AND CONCLUSION:


In this lab, we demonstrated our comprehension of deadlock avoidance algorithm by crafting
a program for Banker’s Algorith through the implementation of various C programming
library files.
TITLE: IMPLEMENTATION OF MEMORY ALLOCATION TECHINQUES.

OBJECTIVE:
i) To learn about the different memory allocation techniques for efficient memory
management in a system.

THEORY:
Memory allocation techniques are used to assign memory blocks to processes in an efficient
manner. Contiguous memory allocation assigns a single contiguous block of memory to a
process, simplifying access but potentially leading to fragmentation.
Paging divides memory into fixed-size pages, allowing non-contiguous allocation and
reducing fragmentation, but introducing overhead for page management. Segmentation
divides memory into segments of varying sizes, where each segment corresponds to a logical
unit, such as a function or data array.
Virtual memory combines both paging and segmentation, enabling the system to use disk
space as an extension of RAM, thus supporting processes larger than physical memory. The
choice of memory allocation technique depends on the system's needs, with the goal of
reducing fragmentation, improving memory utilization, and ensuring efficient execution of
processes. Proper memory allocation techniques enhance system performance, resource
utilization, and scalability.
First Fit Memory Allocation Technique

SOURCE CODE:
#include <stdio.h>
void firstFit(int blockSize[], int m, int processSize[], int n)
{
int allocation[n];
int i, j; // Declare variables outside the for loop for older C standards

// Initialize all allocations to -1 (indicating no allocation yet)


for (i = 0; i < n; i++)
{
allocation[i] = -1;
}
// Loop through each process and find the first block that fits
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
if (blockSize[j] >= processSize[i])
{
allocation[i] = j; // Allocate block j to process i

// Reduce available memory in this block


blockSize[j] -= processSize[i];
break;
}
}
}
// Print the results
printf("\nProcess No.\tProcess Size\tBlock No.\n");
for (i = 0; i < n; i++)
{
printf("%d\t\t %d\t\t", i + 1, processSize[i]);
if (allocation[i] != -1)
printf(" %d\n", allocation[i] + 1);
else
printf("Need to wait\n");
}
}

int main()
{
int m, n, i;
printf("Enter the number of memory blocks: ");
scanf("%d", &m);
int blockSize[m];
printf("Enter the sizes of the memory blocks in order: ");
for (i = 0; i < m; i++)
{
scanf("%d", &blockSize[i]);
}
printf("Enter the number of processes: ");
scanf("%d", &n);
int processSize[n];
printf("Enter the sizes of the processes in order: ");
for (i = 0; i < n; i++)
{
scanf("%d", &processSize[i]);
}
firstFit(blockSize, m, processSize, n);
return 0;
}

OUTPUT:
Best Fit Memory Allocation Technique

SOURCE CODE:
#include <stdio.h>
void bestFit(int blockSize[], int m, int processSize[], int n)
{
int allocation[10]; // Array to hold allocation results
int i, j; // Declare variables outside the for loop

// Initialize all allocations to -1 (indicating no allocation yet)


for (i = 0; i < n; i++)
{
allocation[i] = -1;
}
// Loop through each process to find the best block that fits
for (i = 0; i < n; i++)
{
int bestIdx = -1; // Initialize best index

// Iterate through all memory blocks to find the best fit


for (j = 0; j < m; j++)
{
if (blockSize[j] >= processSize[i])
{
// If block can accommodate the process
if (bestIdx == -1 || blockSize[bestIdx] > blockSize[j])
{
bestIdx = j; // Update best index
}
}
}
// If we found a block for the process
if (bestIdx != -1)
{
allocation[i] = bestIdx; // Allocate block to process

// Reduce available memory in this block


blockSize[bestIdx] -= processSize[i];
}
}
// Print the results
printf("\nProcess No.\tProcess Size\tBlock No.\n");
for (i = 0; i < n; i++)
{
printf("%d\t\t%d\t\t", i + 1, processSize[i]);
if (allocation[i] != -1)
{
printf("%d\n", allocation[i] + 1); // Print allocated block number
}
else
{
printf("Need to wait\n"); // Process needs to wait
}
}
}
int main()
{
int m, n, i;
printf("Enter the number of memory blocks: ");
scanf("%d", &m);
int blockSize[10]; // Declare block sizes array with a max size
printf("Enter the sizes of the memory blocks in order: ");
for (i = 0; i < m; i++)
{
scanf("%d", &blockSize[i]);
}
printf("Enter the number of processes: ");
scanf("%d", &n);
int processSize[10]; // Declare process sizes array with a max size
printf("Enter the sizes of the processes in order: ");
for (i = 0; i < n; i++)
{
scanf("%d", &processSize[i]);
}
bestFit(blockSize, m, processSize, n); // Call best fit function
return 0;
}

OUTPUT:
Worst Fit Memory Allocation Technique

SOURCE CODE:
#include <stdio.h>
#include <string.h>

// Function to allocate memory to blocks as per worst fit algorithm


void worstFit(int blockSize[], int m, int processSize[], int n)
{
// Stores block id of the block allocated to a process
int allocation[n];

// Initially no block is assigned to any process


memset(allocation, -1, sizeof(allocation));

// Pick each process and find suitable blocks according to its size
for (int i = 0; i < n; i++)
{
int wstIdx = -1;
for (int j = 0; j < m; j++)
{
if (blockSize[j] >= processSize[i])
{
if (wstIdx == -1 || blockSize[wstIdx] < blockSize[j])
{
wstIdx = j;
}
}
}
// If a block is found for the current process
if (wstIdx != -1)
{
allocation[i] = wstIdx;
blockSize[wstIdx] -= processSize[i];
}
}
printf("\nProcess No.\tProcess Size\tBlock no.\n");
for (int i = 0; i < n; i++)
{
printf(" %d\t\t%d\t\t", i + 1, processSize[i]);
if (allocation[i] != -1)
printf("%d", allocation[i] + 1);
else
printf("Not Allocated");
printf("\n");
}
}
int main()
{
int blockSize[] = {100, 500, 200, 300, 600};
int processSize[] = {212, 417, 112, 426};
int m = sizeof(blockSize) / sizeof(blockSize[0]);
int n = sizeof(processSize) / sizeof(processSize[0]);
worstFit(blockSize, m, processSize, n);
return 0;
}
OUTPUT:

RESULT AND CONCLUSION:


In this lab, we demonstrated our comprehension of memory allocation techniques by crafting
a program to calculate the efficient use of the memory by the processes through the
implementation of various C programming library files.
TITLE: IMPLEMENTATION OF FREE SPACE MANAGEMENT TECHNIQUES.

OBJECTIVE:
i) To learn about the free space management techniques for efficient allocation and de-
allocation of memory or disk space.

THEORY:
Free space management is crucial for tracking and managing unused memory or disk space in
systems, ensuring that resources are efficiently allocated and de-allocated. Common
techniques include the bit vector method, where each bit represents a block of memory or
disk, with 0 indicating free space and 1 indicating allocated space.
Linked list allocation maintains a list of free blocks, where each block contains a pointer to
the next free block, making allocation and de-allocation more flexible. Counting keeps track
of the number of contiguous free blocks, allowing for faster allocation of large contiguous
spaces. Buddy system allocation divides memory into blocks of varying sizes, pairing them
into "buddies" to optimize space usage and reduce fragmentation.
These methods ensure that free space is managed effectively, minimizing fragmentation and
optimizing system performance. Proper implementation of free space management techniques
leads to better resource utilization and faster allocation or de-allocation operations which
results in smooth functioning of the system.
Bit Vector Free Space Management Technique

SOURCE CODE:
#include <stdio.h> // For printf
#include <stdbool.h> // For bool, true, false
#define BLOCKS 16 // Number of blocks
unsigned char bitmap[BLOCKS / 8] = {0};

void set_bit(int index)


{
bitmap[index / 8] |= (1 << (index % 8));
}
void clear_bit(int index)
{
bitmap[index / 8] &= ~(1 << (index % 8));
}
bool is_bit_set(int index)
{
return (bitmap[index / 8] & (1 << (index % 8))) != 0;
}
int allocate_block()
{
int i;
for (i = 0; i < BLOCKS; i++)
{
if (!is_bit_set(i))
{
set_bit(i);
return i;
}
}
return -1;
}
void free_block(int index)
{
if (index >= 0 && index < BLOCKS)
{
clear_bit(index);
}
}
int main()
{
int block1 = allocate_block();
int block2 = allocate_block();
if (block1 != -1)
{
printf("Allocated block %d\n", block1);
}
else
{
printf("Failed to allocate block 1\n");
}
if (block2 != -1)
{
printf("Allocated block %d\n", block2);
}
else
{
printf("Failed to allocate block 2\n");
}
if (block1 != -1)
{
free_block(block1);
printf("Freed block %d\n", block1);
}
return 0;
}

OUTPUT:
Linked List Free Space Management Technique

SOURCE CODE:
#include <stdio.h>
#include <stdlib.h>

// Node structure for free space blocks


struct Node
{
int start; // Starting address of the block
int size; // Size of the block
struct Node* next; // Pointer to the next block
};
// Function to create a new node
struct Node* createNode(int start, int size)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
if (!newNode)
{
printf("Memory allocation failed.\n");
exit(EXIT_FAILURE);
}
newNode->start = start;
newNode->size = size;
newNode->next = NULL;
return newNode;
}
// Function to allocate memory
void allocate(struct Node** freeList, int size)
{
struct Node* current = *freeList;
struct Node* prev = NULL;
while (current)
{
if (current->size >= size)
{
printf("Allocating %d units from block starting at %d.\n", size,
current->start);
current->start += size;
current->size -= size;
if (current->size == 0)
{
if (prev)
{
prev->next = current->next;
}
else
{
*freeList = current->next;
}
free(current);
}
return;
}
prev = current;
current = current->next;
}
printf("Not enough free space to allocate %d units.\n", size);
}
// Function to deallocate memory
void deallocate(struct Node** freeList, int start, int size)
{
struct Node* newNode = createNode(start, size);
struct Node* current = *freeList;
struct Node* prev = NULL;
while (current && current->start < start)
{
prev = current;
current = current->next;
}
// Insert the new block into the list
newNode->next = current;
if (prev)
{
prev->next = newNode;
}
else
{
*freeList = newNode;
}
// Merge adjacent blocks
if (newNode->next && newNode->start + newNode->size == newNode->next->start)
{
newNode->size += newNode->next->size;
struct Node* temp = newNode->next;
newNode->next = temp->next;
free(temp);
}
if (prev && prev->start + prev->size == newNode->start)
{
prev->size += newNode->size;
prev->next = newNode->next;
free(newNode);
}
}
// Function to display the free list
void display(struct Node* freeList)
{
printf("Free list:\n");
while (freeList)
{
printf("Start: %d, Size: %d\n", freeList->start, freeList->size);
freeList = freeList->next;
}
}
int main()
{
struct Node* freeList = NULL;

// Initial free memory blocks


freeList = createNode(0, 100); // Example:Free block of 100 units starting at address 0

// Display initial state


display(freeList);

// Simulate allocation
allocate(&freeList, 20);
display(freeList);
allocate(&freeList, 30);
display(freeList);

// Simulate deallocation
deallocate(&freeList, 20, 10);
display(freeList);
deallocate(&freeList, 50, 10);
display(freeList);
return 0;
}

OUTPUT:

Indexed Free Space Management Technique

SOURCE CODE:
#include <stdio.h>
#include <stdbool.h>
#define TOTAL_BLOCKS 16 // Total number of blocks

// Global variables
int index_block[TOTAL_BLOCKS]; // Indexed free space table
bool block_status[TOTAL_BLOCKS]; // Track block status: true = allocated, false = free
int index_count = 0; // Number of free blocks in the index block
// Initialize free blocks
void initialize_blocks()
{
for (int i = 0; i < TOTAL_BLOCKS; i++)
{
index_block[i] = i; // Add all blocks to the index
block_status[i] = false; // Mark all blocks as free
}
index_count = TOTAL_BLOCKS; // Initialize free block count
}
// Allocate a block
int allocate_block()
{
if (index_count == 0)
{
printf("No free blocks available.\n");
return -1; // No free blocks
}
int allocated_block = index_block[--index_count]; // Get a free block
block_status[allocated_block] = true; // Mark as allocated
printf("Block %d allocated.\n", allocated_block);
return allocated_block;
}
// Free a block
void free_block(int block)
{
if (block < 0 || block >= TOTAL_BLOCKS || !block_status[block])
{
printf("Invalid or already free block: %d\n", block);
return;
}
block_status[block] = false; // Mark as free
index_block[index_count++] = block; // Add back to the index
printf("Block %d freed.\n", block);
}
// Display the current index block
void display_index_block()
{
printf("Index Block (Free Blocks): ");
for (int i = 0; i < index_count; i++)
{
printf("%d ", index_block[i]);
}
printf("\n");
}
// Display block allocation status
void display_block_status()
{
printf("Block Status: ");
for (int i = 0; i < TOTAL_BLOCKS; i++)
{
printf("%d[%c] ", i, block_status[i] ? 'A' : 'F'); // A = Allocated, F = Free
}
printf("\n");
}
int main()
{
initialize_blocks(); // Initialize the blocks

// Display initial state


display_index_block();
display_block_status();

// Allocate some blocks


allocate_block();
allocate_block();
allocate_block();

// Display state after allocation


display_index_block();
display_block_status();

// Free a block
free_block(1);

// Display state after freeing


display_index_block();
display_block_status();
return 0;
}

OUTPUT:
RESULT AND CONCLUSION:
In this lab, we demonstrated our comprehension of free space management techniques by
crafting a program to find block status through the implementation of various C programming
library files.
TITLE: IMPLEMENTATION OF PAGE REPLACEMENT ALGORITHMS.

OBJECTIVE:
i) To learn about the page replacement algorithms that optimize memory management
by determining which pages to swap in and out of physical memory.

THEORY:
Page replacement algorithms are used in virtual memory systems to decide which pages
should be swapped out when physical memory is full. Common algorithms include First-In-
First-Out (FIFO), which replaces the oldest page in memory, regardless of how frequently it
is used. Least Recently Used (LRU) replaces the page that has not been used for the longest
period, aiming to keep the most recently accessed pages in memory.
Similarly,Optimal Page Replacement chooses the page that will not be used for the longest
time in the future, providing the best possible performance but being impractical to
implement in real systems since future page requests are unknown. Clock is a more efficient
approximation of LRU, using a circular buffer and a reference bit to track page usage.
Page replacement algorithms aim to minimize page faults and optimize memory utilization,
enhancing system performance by ensuring that frequently used pages are readily available in
memory while less frequently used pages are swapped out. Proper implementation reduces
overhead and increases system responsiveness.
First-In-First-Out (FIFO) Page Replacement Algorithm

SOURCE CODE:
#include <stdio.h>
int main()
{
int capacity, n, page_faults = 0, page_hits = 0, front = 0;
printf("Enter the number of frames: ");
scanf("%d", &capacity); // Number of frames available (capacity of memory)
printf("Enter the number of page requests: ");
scanf("%d", &n); // Number of pages (sequence length)

// Declare frames and pages arrays


int frames[100]; // Frames to hold the pages (Assuming a max capacity of 100)
int pages[100]; /* Array for page requests (Assuming a max number of page requests
of 100)*/
int filled = 0; // Number of pages currently filled in frames
int i, j; // Loop variables
// Initialize all frames to -1 (indicating they are empty)
for (i = 0; i < capacity; i++)
{
frames[i] = -1;
}
// Input the page sequence
printf("Enter the page reference string: ");
for (i = 0; i < n; i++)
{
scanf("%d", &pages[i]);
}
// Iterate over each page in the reference string
for (i = 0; i < n; i++)
{
int page = pages[i];
int found = 0; // Flag to check if the page is already in frame

// Check if the page is already in one of the frames (page hit)


for (j = 0; j < filled; j++)
{
if (frames[j] == page)
{
found = 1;
break;
}
}
// Display the current page request
printf("Page %2d: ", page);

// If the page is found, it's a hit


if (found)
{
page_hits++;
}
else
{
// If the page is not found, it's a fault
if (filled < capacity)
{
// If there is still space in the frames
frames[filled] = page;
filled++;
}
else
{
// Replace the oldest page (FIFO)
frames[front] = page;
front = (front + 1) % capacity; // Move to next position in FIFO
}
page_faults++;
}
// Display the current state of the frames with uniform spacing
for (j = 0; j < capacity; j++)
{
if (frames[j] == -1)
printf(" - ");
else
printf("%3d ", frames[j]);
}
// Indicate hit or fault
if (found)
{
printf("[ H ]\n");
}
else
{
printf("[ F ]\n");
}
}
// Output the total number of page faults and hits
printf("\nTotal Page Faults: %d\n", page_faults);
printf("Total Page Hits: %d\n", page_hits);
return 0;
}
OUTPUT:

Least Recently Used (LRU) Page Replacement Algorithm

SOURCE CODE:
#include <stdio.h>
struct Page
{
int value; // Page value
int frequency; // Frequency of usage
int last_used; // Last used time for LFU tie-breaking
};
int main()
{
int capacity, n, page_faults = 0, page_hits = 0, time = 0;

// Get the number of frames


printf("Enter the number of frames: ");
scanf("%d", &capacity); // Number of frames available (capacity of memory)

// Get the number of page requests


printf("Enter the number of page requests: ");
scanf("%d", &n); // Number of pages (sequence length)

// Declare arrays with fixed sizes


struct Page frames[100]; /*Frames to hold the pages and their frequency (assuming a
max of 100 frames)*/
int pages[100]; // Array for page requests (assuming a max of 100 page requests)

// Initialize frames (set page value to -1 and frequency to 0)


int i; // Loop variable
for (i = 0; i < capacity; i++)
{
frames[i].value = -1;
frames[i].frequency = 0;
frames[i].last_used = 0;
}
// Input the page sequence
printf("Enter the page reference string: ");
for (i = 0; i < n; i++)
{
scanf("%d", &pages[i]);
}
// Iterate over each page in the reference string
for (i = 0; i < n; i++)
{
int page = pages[i];
int found = 0; // Flag to check if the page is already in frame
time++; // Update the time for LFU tie-breaking

// Check if the page is already in one of the frames (page hit)


int j; // Loop variable for frame checking
for (j = 0; j < capacity; j++)
{
if (frames[j].value == page)
{
found = 1;
frames[j].frequency++; // Increment frequency on hit
frames[j].last_used = time; // Update the last used time
break;
}
}
// Display the current page request
printf("Page %2d: ", page);

// If page is found, it's a hit


if (found)
{
page_hits++;
}
else
{
// If page is not found, it's a fault
page_faults++;
// Find the frame to replace using LFU logic
int min_freq = frames[0].frequency, replace_idx = 0;
for (j = 1; j < capacity; j++)
{
/* Replace the least frequently used page or in case of tie, the
least recently used page */
if (frames[j].frequency < min_freq ||
(frames[j].frequency == min_freq &&
frames[j].last_used < frames[replace_idx].last_used))
{
min_freq = frames[j].frequency;
replace_idx = j;
}
}
// Replace the page in the chosen frame
frames[replace_idx].value = page;
frames[replace_idx].frequency = 1; // Initialize frequency to 1
frames[replace_idx].last_used = time; // Update the last used time
}
// Display the current state of the frames with uniform spacing
for (j = 0; j < capacity; j++)
{
if (frames[j].value == -1)
printf(" - ");
else
printf("%3d ", frames[j].value);
}

// Indicate hit or fault


if (found)
{
printf("[ H ]\n");
}
else
{
printf("[ F ]\n");
}
}
// Output the total number of page faults and hits
printf("\nTotal Page Faults: %d\n", page_faults);
printf("Total Page Hits: %d\n", page_hits);
return 0;
}

OUTPUT:
Optimal Page Replacement Algorithm

SOURCE CODE:
#include <stdio.h>
int find_farthest(int pages[], int frames[], int n, int current_index, int capacity)
{
int farthest_index = -1;
int farthest_distance = -1;
int i, j; // Declare loop variables here
for (i = 0; i < capacity; i++)
{
// Check how far this page is used in the future
for (j = current_index + 1; j < n; j++)
{
if (frames[i] == pages[j])
{
if (j > farthest_distance)
{
farthest_distance = j;
farthest_index = i;
}
break; // Break if the page is found
}
}
// If the page is not used in the future at all
if (j == n)
{
return i; // Replace this page since it's never used again
}
}
return (farthest_index == -1) ? 0 : farthest_index;
}
int main()
{
int capacity, n, page_faults = 0, page_hits = 0;
int filled = 0; // Number of pages in frames currently filled

// Get the number of frames


printf("Enter the number of frames: ");
scanf("%d", &capacity); // Number of frames available (capacity of memory)

// Get the number of page requests


printf("Enter the number of page requests: ");
scanf("%d", &n); // Number of pages (sequence length)

// Declare arrays with fixed sizes


int frames[100]; // Frames to hold the pages (assuming a max of 100 frames)
int pages[100]; // Array for page requests (assuming a max of 100 page requests)

// Initialize all frames to -1 (indicating they are empty)


int i; // Declare loop variable
for (i = 0; i < capacity; i++)
{
frames[i] = -1;
}
// Input the page sequence
printf("Enter the page reference string: ");
for (i = 0; i < n; i++)
{
scanf("%d", &pages[i]);
}
// Iterate over each page in the reference string
for (i = 0; i < n; i++)
{
int page = pages[i];
int found = 0; // Flag to check if page is already in frame
int j; // Declare j here for the loop

// Check if the page is already in one of the frames (page hit)


for (j = 0; j < filled; j++)
{
if (frames[j] == page)
{
found = 1;
break;
}
}
// Display the current page request
printf("Page %2d: ", page);

// If page is found, it's a hit


if (found)
{
page_hits++;
}
else
{
// If page is not found, it's a fault
page_faults++;
if (filled < capacity)
{
// If there is still space in the frames
frames[filled] = page;
filled++;
}
else
{
// Find the page that is used farthest in the future and replace it
int farthest_index = find_farthest(pages, frames, n, i, capacity);
frames[farthest_index] = page;
}
}
// Display the current state of the frames with uniform spacing
for (j = 0; j < capacity; j++)
{
if (frames[j] == -1)
printf(" - ");
else
printf("%3d ", frames[j]);
}
// Indicate hit or fault
if (found)
{
printf("[ H ]\n");
}
else
{
printf("[ F ]\n");
}
}
// Output the total number of page faults and hits
printf("\nTotal Page Faults: %d\n", page_faults);
printf("Total Page Hits: %d\n", page_hits);
return 0;
}

OUTPUT:

Second Chance Page Replacement Algorithm

SOURCE CODE:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

// Function to find an element in the queue


// Returns the index if found, -1 otherwise
int findPage(int *q, int size, int x)
{
int i; // Declare loop variable outside the for loop
for (i = 0; i < size; i++)
{
if (q[i] == x)
return i;
}
return -1;
}
// Function to implement the Second Chance Page Replacement Algorithm
void Second_Chance_Replacement(int *t, int n, int capacity)
{
int *q = (int *)malloc(capacity * sizeof(int)); // Queue implementation using array
bool *bitref = (bool *)malloc(capacity * sizeof(bool)); // Reference bits
int qSize = 0; // Current size of queue

// Variables to track hits and faults


int hits = 0, faults = 0;
int ptr = 0; // Pointer to track the position in the queue

// Initialize the reference bits array


int i; // Declare loop variable for initialization
for (i = 0; i < capacity; i++)
{
bitref[i] = false;
}

for (i = 0; i < n; i++)


{
int pageIndex = findPage(q, qSize, t[i]);

// If the page is already in memory (hit)


if (pageIndex != -1)
{
hits++;
bitref[pageIndex] = true; // Set reference bit to 1 (second chance)
}
// If it's a fault (page not found in memory)
else
{
faults++;

// If there's still room in the queue


if (qSize < capacity)
{
q[qSize] = t[i]; // Insert page into memory
bitref[qSize] = false; // Initially set reference bit to 0
qSize++;
}
// If the queue is full, apply the Second Chance algorithm
else
{
while (true)
{
/* Check the reference bit of the page at the current
pointer position*/
if (bitref[ptr] == false)
{
// If reference bit is 0, replace the page
q[ptr] = t[i];
// Set reference bit for the replaced page
bitref[ptr] = false;
break;
}
else
{
/* If reference bit is 1, reset it and move to the
next page */
bitref[ptr] = false;
ptr = (ptr + 1) % capacity; // Circular increment
}
}
// Move pointer to the next position after replacement
ptr = (ptr + 1) % capacity;
}
}
}
printf("Hits: %d\nFaults: %d\n", hits, faults);

// Free dynamically allocated memory


free(q);
free(bitref);
}
int main()
{
int t[] = { 7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 3};
int n = sizeof(t) / sizeof(t[0]);
int capacity = 3;
Second_Chance_Replacement(t, n, capacity);
return 0;
}
OUTPUT:

RESULT AND CONCLUSION:


In this lab, we demonstrated our comprehension of page replacement algorithms by crafting a
program to find page faults and page hits in a page reference string through the
implementation of various C programming library files.
TITLE: IMPLEMENTATION OF FILE ALLOCATION TECHNIQUES.

OBJECTIVE:
i) To learn about the file allocation techniques for efficient storage, retrieval, and
management of files on a disk.

THEORY:
File allocation techniques manage how files are stored on a disk to optimize space utilization
and access time. Contiguous allocation stores a file in consecutive blocks on the disk,
providing fast access but leading to fragmentation and limited flexibility.
Linked allocation uses a linked list where each file block points to the next, eliminating
fragmentation but slowing access due to sequential traversal. Indexed allocation maintains an
index block for each file, containing pointers to its data blocks, combining efficient access
and flexibility but requiring extra storage for index blocks. Advanced techniques like multi-
level indexing and hashed allocation further improve performance and reliability in specific
scenarios.
Each technique has its advantages and trade-offs in terms of speed, space utilization, and
complexity. Implementing these techniques helps to optimize file storage and ensures
efficient disk space management in a file system so that the each required files can be
accessed easily.
Sequential File Allocation Technique

SOURCE CODE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_FILES 10
#define MAX_NAME_LENGTH 20
#define DISK_SIZE 100

// Structure to represent a file


struct File
{
char name[MAX_NAME_LENGTH];
int size;
int startBlock;
};
// Structure to represent the disk
struct Disk
{
char blocks[DISK_SIZE]; // '0' indicates free, '1' indicates allocated
struct File files[MAX_FILES];
int fileCount;
};
// Function to initialize the disk
void initializeDisk(struct Disk *disk)
{
for (int i = 0; i < DISK_SIZE; i++)
{
disk->blocks[i] = '0'; // Mark all blocks as free
}
disk->fileCount = 0;
}
// Function to allocate a file sequentially
int allocateFile(struct Disk *disk, const char *name, int size)
{
// Check if the file count exceeds the maximum allowed files
if (disk->fileCount >= MAX_FILES)
{
printf("Error: Maximum number of files reached.\n");
return -1;
}
// Find a contiguous space in the disk
int start = -1, count = 0;
for (int i = 0; i < DISK_SIZE; i++)
{
if (disk->blocks[i] == '0')
{
// Free block
if (start == -1)
{
start = i; // Mark the start of a potential allocation
}
count++; // Increment count of contiguous free blocks
if (count == size)
{
// Enough space found
// Allocate the file
struct File newFile;
strcpy(newFile.name, name);
newFile.size = size;
newFile.startBlock = start;
for (int j = start; j < start + size; j++)
{
disk->blocks[j] = '1'; // Mark blocks as allocated
}
// Add file to the disk
disk->files[disk->fileCount++] = newFile;
printf("File '%s' allocated at block %d.\n", name, start);
return 0; // Success
}
}
else
{
// Reset if we hit an allocated block
start = -1;
count = 0;
}
}
printf("Error: Not enough contiguous space to allocate file '%s'.\n", name);
return -1; // Allocation failed
}
// Function to display the current state of the disk
void displayDiskState(struct Disk *disk)
{
printf("\nDisk State:\n");
for (int i = 0; i < DISK_SIZE; i++)
{
printf("%c ", disk->blocks[i]);
}
printf("\n\nAllocated Files:\n");
for (int i = 0; i < disk->fileCount; i++)
{
printf("File Name: %s, Size: %d, Starting Block: %d\n", disk->files[i].name,
disk->files[i].size, disk->files[i].startBlock);
}
}
int main()
{
struct Disk disk;
initializeDisk(&disk);

// Simulate file allocations


allocateFile(&disk, "File1.txt", 10);
allocateFile(&disk, "File2.txt", 20);
allocateFile(&disk, "File3.txt", 5);
allocateFile(&disk, "File4.txt", 15);
allocateFile(&disk, "File5.txt", 30); // This should fail
displayDiskState(&disk);
return 0;
}

OUTPUT:

Linked File Allocation Technique

SOURCE CODE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_FILES 10
#define DISK_SIZE 20
#define MAX_NAME_LENGTH 20

// Structure to represent a block in the disk


struct Block
{
int nextBlock; // Index of the next block; -1 if no next block
char data[50]; // Data stored in the block (can be the file name)
};
// Structure to represent a file
struct File
{
char name[MAX_NAME_LENGTH];
int startBlock; // Starting block index of the file
int size; // Size of the file in blocks
};
// Structure to represent the disk
struct Disk
{
struct Block blocks[DISK_SIZE]; // Array of blocks
struct File files[MAX_FILES]; // Array of files
int fileCount; // Number of files currently allocated
};
// Function to initialize the disk
void initializeDisk(struct Disk *disk)
{
for (int i = 0; i < DISK_SIZE; i++)
{
disk->blocks[i].nextBlock = -1; // Initialize nextBlock as -1 (no next block)
strcpy(disk->blocks[i].data, ""); // Initialize data as empty
}
disk->fileCount = 0;
}
// Function to allocate a file using linked allocation
int allocateFile(struct Disk *disk, const char *name, int size)
{
if (disk->fileCount >= MAX_FILES)
{
printf("Error: Maximum number of files reached.\n");
return -1;
}
int previousBlock = -1; // To keep track of the previous block
int firstBlock = -1; // To keep track of the first block
// Find free blocks for allocation
for (int i = 0; i < DISK_SIZE; i++)
{
if (disk->blocks[i].nextBlock == -1 && strcmp(disk->blocks[i].data, "") == 0)
{
// Allocate the block
if (firstBlock == -1)
{
firstBlock = i; // Mark the first block
}
else
{
// Link the previous block to the current block
disk->blocks[previousBlock].nextBlock = i;
}
previousBlock = i; // Update the previous block index

// Store the file name in the block data


snprintf(disk->blocks[i].data, sizeof(disk->blocks[i].data), "%s",
name);
size--; // Decrease the size of the file being allocated
if (size == 0)
{
// If the file is fully allocated
break;
}
}
}
// Check if the file was fully allocated
if (size > 0)
{
printf("Error: Not enough space to allocate file '%s'.\n", name);
return -1; // Allocation failed
}
// Set the nextBlock of the last allocated block to -1
if (previousBlock != -1)
{
disk->blocks[previousBlock].nextBlock = -1; // End of the linked list
}
// Store the file information
struct File newFile;
strcpy(newFile.name, name);
newFile.startBlock = firstBlock;
newFile.size = previousBlock - firstBlock + 1; // Calculatesize of the file in blocks
disk->files[disk->fileCount++] = newFile; // Add file to the disk
printf("File '%s' allocated starting at block %d.\n", name, firstBlock);
return 0; // Success
}
// Function to display the current state of the disk
void displayDiskState(struct Disk *disk)
{
printf("\nDisk State:\n");
for (int i = 0; i < DISK_SIZE; i++)
{
printf("[Block %2d]: %s (Next: %d) ", i, disk->blocks[i].data,
disk->blocks[i].nextBlock);
}
printf("\n\nAllocated Files:\n");
for (int i = 0; i < disk->fileCount; i++)
{
printf("File Name: %s, Starting Block: %d, Size: %d\n", disk->files[i].name,
disk->files[i].startBlock, disk->files[i].size);
}
}
int main()
{
struct Disk disk;
initializeDisk(&disk);

// Simulate file allocations


allocateFile(&disk, "File1.txt", 3);
allocateFile(&disk, "File2.txt", 4);
allocateFile(&disk, "File3.txt", 2);
allocateFile(&disk, "File4.txt", 5);
allocateFile(&disk, "File5.txt", 3); // This should succeed

displayDiskState(&disk);
return 0;
}

OUTPUT:
Indexed File Allocation Technique

SOURCE CODE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_FILES 10
#define DISK_SIZE 20
#define MAX_NAME_LENGTH 20
#define MAX_INDEX_BLOCKS 5 // Max number of blocks a single file can use

// Structure to represent a block in the disk


struct Block
{
char data[50]; // Data stored in the block (can be the file name)
};
// Structure to represent a file with its index
struct File
{
char name[MAX_NAME_LENGTH];
int index[MAX_INDEX_BLOCKS]; // Index blocks used by the file
int size; // Number of blocks allocated
};
// Structure to represent the disk
struct Disk
{
struct Block blocks[DISK_SIZE]; // Array of blocks
struct File files[MAX_FILES]; // Array of files
int fileCount; // Number of files currently allocated
};
// Function to initialize the disk
void initializeDisk(struct Disk *disk)
{
int i;
for (i = 0; i < DISK_SIZE; i++)
{
strcpy(disk->blocks[i].data, ""); // Initialize data as empty
}
disk->fileCount = 0;
}
// Function to allocate a file using indexed allocation
int allocateFile(struct Disk *disk, const char *name, int size)
{
if (disk->fileCount >= MAX_FILES)
{
printf("Error: Maximum number of files reached.\n");
return -1;
}
struct File newFile;
strcpy(newFile.name, name);
newFile.size = 0; // Initialize size to 0

// Find free blocks for allocation


for (int i = 0; i < DISK_SIZE; i++)
{
if (newFile.size < size && strcmp(disk->blocks[i].data, "") == 0)
{
// Check if block is free
// Allocate the block
snprintf(disk->blocks[i].data, sizeof(disk->blocks[i].data), "%s",
name);
// Store the index of the allocated block
newFile.index[newFile.size++] = I;
}
}
// Check if the file was fully allocated
if (newFile.size < size)
{
printf("Error: Not enough space to allocate file '%s'. Only %d blocks
allocated.\n", name, newFile.size);
return -1; // Allocation failed
}
// Store the file information
disk->files[disk->fileCount++] = newFile; // Add file to the disk
printf("File '%s' allocated at blocks:", name);
for (int j = 0; j < newFile.size; j++)
{
printf(" %d", newFile.index[j]);
}
printf("\n");
return 0; // Success
}
// Function to display the current state of the disk
void displayDiskState(struct Disk *disk)
{
int i;
printf("\nDisk State:\n");
for (i = 0; i < DISK_SIZE; i++)
{
printf("[Block %2d]: %s ", i, disk->blocks[i].data);
}
printf("\n\nAllocated Files:\n");
for (i = 0; i < disk->fileCount; i++)
{
printf("File Name: %s, Index Blocks: ", disk->files[i].name);
for (int j = 0; j < disk->files[i].size; j++)
{
printf("%d ", disk->files[i].index[j]);
}
printf("\n");
}
}
int main()
{
struct Disk disk;
initializeDisk(&disk);

// Simulate file allocations


allocateFile(&disk, "File1.txt", 3);
allocateFile(&disk, "File2.txt", 2);
allocateFile(&disk, "File3.txt", 4);
allocateFile(&disk, "File4.txt", 1);
allocateFile(&disk, "File5.txt", 2); // This should succeed

displayDiskState(&disk);
return 0;
}

OUTPUT:
RESULT AND CONCLUSION:
In this lab, we demonstrated our comprehension of file allocation techniques by crafting a
program to locate various files in the system through the implementation of various C
programming library files.
TITLE: IMPLEMENTATION OF DISK SCHEDULING ALGORITHMS.

OBJECTIVE:
i) To learn about the disk scheduling algorithms for optimizing disk access time and
improving overall system performance.

THEORY:
Disk scheduling algorithms determine the order in which disk I/O requests are processed to
minimize seek time and improve throughput. First-Come-First-Serve (FCFS) processes
requests in the order they arrive, which is simple but may lead to long seek times. Shortest
Seek Time First (SSTF) selects the request closest to the current head position, reducing seek
time but potentially causing starvation for distant requests.
Similarly, SCAN and C-SCAN move the disk head in a specific direction, servicing requests
along the way, and reverse or reset direction at the end, providing fairness and reducing
variance in access time. LOOK and C-LOOK are variants of SCAN and C-SCAN that only
move as far as the furthest request, further optimizing performance.
These algorithms aim to balance efficiency, fairness, and responsiveness in handling disk I/O.
Proper implementation ensures reduced latency, improved disk utilization, and better end-
user experience in storage-intensive applications.
First-Come-First-Serve (FCFS) Disk Scheduling Algorithm

SOURCE CODE:
#include<stdio.h>
#include<stdlib.h>
void FCFS(int requests[], int n, int head)
{
int total_head_movement = 0;
int i; // Declare the loop variable outside the for loop

// Display the initial head position


printf("Initial Head Position: %d\n", head);
printf("Disk Head Movement Sequence:\n");

// Service each request in the order they appear


for (i = 0; i < n; i++)
{
// Display the movement from the current head to the next request
printf("%d -> %d\n", head, requests[i]);

// Calculate the head movement for the current request


int movement = abs(requests[i] - head);
total_head_movement += movement;

// Move the head to the current request's position


head = requests[i];
}
// Display the total head movement
printf("Total Distance Covered in Tracks: %d\n", total_head_movement);
}
int main()
{
// Self-initialized values for disk requests and head position
int requests[] = {95, 180, 34, 119, 11, 123, 62, 64};
int n = sizeof(requests) / sizeof(requests[0]); // Number of disk requests
int head = 50; // Initial position of the disk head

// Run FCFS Disk Scheduling Algorithm


FCFS(requests, n, head);
return 0;
}
OUTPUT:

Shortest Seek Time First (SSTF) Disk Scheduling Algorithm

SOURCE CODE:
#include <stdio.h>
#include <stdlib.h>
void SSTF(int requests[], int n, int head)
{
int total_head_movement = 0;
int completed[100] = {0}; // To track completed requests
int current_index, i;

// Display the initial head position


printf("Initial Head Position: %d\n", head);
printf("Disk Head Movement Sequence:\n");
for (int count = 0; count < n; count++)
{
int min_distance = 10000; // Set to a large value
int closest_index = -1;

// Find the closest request


for (i = 0; i < n; i++)
{
if (!completed[i])
{
// Check if request is not completed
int distance = abs(requests[i] - head);
if (distance < min_distance)
{
min_distance = distance;
closest_index = i; // Update closest request
}
}
}
// Move the head to the closest request
if (closest_index != -1)
{
printf("%d -> %d\n", head, requests[closest_index]);
total_head_movement += min_distance;
head = requests[closest_index];
completed[closest_index] = 1; // Mark as completed
}
}
// Display the total head movement
printf("Total Distance Covered in Tracks: %d\n", total_head_movement);
}
int main()
{
// Self-initialized values for disk requests and head position
int requests[] = {95, 180, 34, 119, 11, 123, 62, 64};
int n = sizeof(requests) / sizeof(requests[0]); // Number of disk requests
int head = 50; // Initial position of the disk head
// Run SSTF Disk Scheduling Algorithm
SSTF(requests, n, head);
return 0;
}

OUTPUT:

SCAN Disk Scheduling Algorithm

SOURCE CODE:
#include <stdio.h>
#include <stdlib.h>
void SCAN(int requests[], int n, int head, int direction)
{
int total_head_movement = 0;
int current_index, i;

// Display the initial head position


printf("Initial Head Position: %d\n", head);
printf("Disk Head Movement Sequence:\n");

// Sort the requests


for (i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
if (requests[i] > requests[j])
{
int temp = requests[i];
requests[i] = requests[j];
requests[j] = temp;
}
}
}
// Determine the position of the head in the sorted array
for (i = 0; i < n; i++)
{
if (requests[i] >= head)
{
current_index = i;
break;
}
}
// Move in the specified direction
if (direction == 1)
{
// Moving right
// Service requests to the right of the head
for (i = current_index; i < n; i++)
{
printf("%d -> %d\n", head, requests[i]);
total_head_movement += abs(requests[i] - head);
head = requests[i];
}
// Move to the end of the disk and then service requests to the left
printf("%d -> %d\n", head, 199); // Assuming the disk size is 200
total_head_movement += abs(199 - head);
head = 199;
for (i = n - 1; i >= 0; i--)
{
printf("%d -> %d\n", head, requests[i]);
total_head_movement += abs(requests[i] - head);
head = requests[i];
}
}
else
{
// Moving left
// Service requests to the left of the head
for (i = current_index - 1; i >= 0; i--)
{
printf("%d -> %d\n", head, requests[i]);
total_head_movement += abs(requests[i] - head);
head = requests[i];
}
// Move to the start of the disk and then service requests to the right
printf("%d -> %d\n", head, 0);
total_head_movement += abs(0 - head);
head = 0;
for (i = 0; i < n; i++)
{
printf("%d -> %d\n", head, requests[i]);
total_head_movement += abs(requests[i] - head);
head = requests[i];
}
}
// Display the total head movement
printf("Total Distance Covered in Tracks: %d\n", total_head_movement);
}
int main()
{
// Self-initialized values for disk requests and head position
int requests[] = {95, 180, 34, 119, 11, 123, 62, 64};
int n = sizeof(requests) / sizeof(requests[0]); // Number of disk requests
int head = 50; // Initial position of the disk head
int direction = 1; // 1 for right, 0 for left

// Run SCAN Disk Scheduling Algorithm


SCAN(requests, n, head, direction);
return 0;
}

OUTPUT:
C-SCAN Disk Scheduling Algorithm

SOURCE CODE:
#include <stdio.h>
#include <stdlib.h>
void C_SCAN_Top_Bottom(int requests[], int n, int head, int disk_size)
{
int total_head_movement = 0;
int sorted_requests[n + 2]; // Include 2 more for the boundary points,0 and disk_size-1
int i, j;

// Copy the requests and add the boundary points (0 and disk_size - 1)
for (i = 0; i < n; i++)
sorted_requests[i] = requests[i];

sorted_requests[n] = 0; // Add the lowest track (0)


sorted_requests[n + 1] = disk_size - 1; // Add the highest track (disk_size - 1)

// Sort the request array along with boundary points


for (i = 0; i < n + 2; i++)
{
for (j = i + 1; j < n + 2; j++)
{
if (sorted_requests[i] > sorted_requests[j])
{
int temp = sorted_requests[i];
sorted_requests[i] = sorted_requests[j];
sorted_requests[j] = temp;
}
}
}
// Display the initial head position
printf("Initial Head Position: %d\n", head);
printf("Disk Head Movement Sequence (Top-Bottom C-SCAN Approach):\n");

// Find the position of the head in the sorted array


int start_index = 0;
for (i = 0; i < n + 2; i++)
{
if (sorted_requests[i] >= head)
{
start_index = i;
break;
}
}
// Move Upwards (Top-Down)
for (i = start_index; i < n + 2; i++)
{
printf("%d -> %d\n", head, sorted_requests[i]);
total_head_movement += abs(sorted_requests[i] - head);
head = sorted_requests[i];
}
// Jump directly from the highest track to the lowest track (Circular behavior)
if (head != 0)
{
printf("%d -> 0 (Jump)\n", head);
total_head_movement += abs(head - 0);
head = 0;
}
// Move Upwards again from the lowest track
for (i = 0; i < start_index; i++)
{
printf("%d -> %d\n", head, sorted_requests[i]);
total_head_movement += abs(sorted_requests[i] - head);
head = sorted_requests[i];
}
// Display the total head movement
printf("Total Distance Covered in Tracks (Top-Bottom C-SCAN): %d\n",
total_head_movement);
}
void C_SCAN_Bottom_Top(int requests[], int n, int head, int disk_size)
{
int total_head_movement = 0;
int sorted_requests[n + 2]; // Include 2 more for the boundary points,0 and disk_size-1
int i, j;

// Copy the requests and add the boundary points (0 and disk_size - 1)
for (i = 0; i < n; i++)
sorted_requests[i] = requests[i];

sorted_requests[n] = 0; // Add the lowest track (0)


sorted_requests[n + 1] = disk_size - 1; // Add the highest track (disk_size - 1)

// Sort the request array along with boundary points


for (i = 0; i < n + 2; i++)
{
for (j = i + 1; j < n + 2; j++)
{
if (sorted_requests[i] > sorted_requests[j])
{
int temp = sorted_requests[i];
sorted_requests[i] = sorted_requests[j];
sorted_requests[j] = temp;
}
}
}
// Display the initial head position
printf("\nInitial Head Position: %d\n", head);
printf("Disk Head Movement Sequence (Bottom-Top C-SCAN Approach):\n");

// Find the position of the head in the sorted array


int start_index = 0;
for (i = 0; i < n + 2; i++)
{
if (sorted_requests[i] >= head)
{
start_index = i;
break;
}
}
// Move Downwards (Bottom-Up)
for (i = start_index - 1; i >= 0; i--)
{
printf("%d -> %d\n", head, sorted_requests[i]);
total_head_movement += abs(sorted_requests[i] - head);
head = sorted_requests[i];
}
// Jump directly from the lowest track to the highest track (Circular behavior)
if (head != disk_size - 1)
{
printf("%d -> %d (Jump)\n", head, disk_size - 1);
total_head_movement += abs(head - (disk_size - 1));
head = disk_size - 1;
}
// Move Downwards again from the highest track
for (i = n + 1; i >= start_index; i--)
{
printf("%d -> %d\n", head, sorted_requests[i]);
total_head_movement += abs(sorted_requests[i] - head);
head = sorted_requests[i];
}
// Display the total head movement
printf("Total Distance Covered in Tracks (Bottom-Top C-SCAN): %d\n",
total_head_movement);
}
int main()
{
// Self-initialized values for disk requests and head position
int requests[] = {95, 180, 34, 119, 11, 123, 62, 64}; // Disk request queue
int n = sizeof(requests) / sizeof(requests[0]); // Number of disk requests
int head = 50;

// Initial position of the disk hea


int disk_size = 200; // Size of the disk (number of tracks)

// Run C-SCAN Disk Scheduling Algorithm (Top-Bottom approach)


C_SCAN_Top_Bottom(requests, n, head, disk_size);

// Run C-SCAN Disk Scheduling Algorithm (Bottom-Top approach)


C_SCAN_Bottom_Top(requests, n, head, disk_size);
return 0;
}
OUTPUT:

LOOK Disk Scheduling Algorithm

SOURCE CODE:
#include <stdio.h>
#include <stdlib.h>
void LOOK_Top_Bottom(int requests[], int n, int head)
{
int total_head_movement = 0;
int sorted_requests[n]; // Array to store sorted requests
int i, j;

// Copy the requests


for (i = 0; i < n; i++)
sorted_requests[i] = requests[i];

// Sort the request array


for (i = 0; i < n; i++)
{
for (j = i + 1; j < n; j++)
{
if (sorted_requests[i] > sorted_requests[j])
{
int temp = sorted_requests[i];
sorted_requests[i] = sorted_requests[j];
sorted_requests[j] = temp;
}
}
}
// Display the initial head position
printf("Initial Head Position: %d\n", head);
printf("Disk Head Movement Sequence (Top-Bottom LOOK Approach):\n");

// Find the position of the head in the sorted array


int start_index = 0;
for (i = 0; i < n; i++)
{
if (sorted_requests[i] >= head)
{
start_index = i;
break;
}
}
// Move Upwards (Top-Down)
for (i = start_index; i < n; i++)
{
printf("%d -> %d\n", head, sorted_requests[i]);
total_head_movement += abs(sorted_requests[i] - head);
head = sorted_requests[i];
}
// After reaching the highest request, reverse direction
for (i = start_index - 1; i >= 0; i--)
{
printf("%d -> %d\n", head, sorted_requests[i]);
total_head_movement += abs(sorted_requests[i] - head);
head = sorted_requests[i];
}
// Display the total head movement
printf("Total Distance Covered in Tracks (Top-Bottom LOOK): %d\n",
total_head_movement);
}
void LOOK_Bottom_Top(int requests[], int n, int head)
{
int total_head_movement = 0;
int sorted_requests[n]; // Array to store sorted requests
int i, j;

// Copy the requests


for (i = 0; i < n; i++)
sorted_requests[i] = requests[i];

// Sort the request array


for (i = 0; i < n; i++)
{
for (j = i + 1; j < n; j++)
{
if (sorted_requests[i] > sorted_requests[j])
{
int temp = sorted_requests[i];
sorted_requests[i] = sorted_requests[j];
sorted_requests[j] = temp;
}
}
}
// Display the initial head position
printf("\nInitial Head Position: %d\n", head);
printf("Disk Head Movement Sequence (Bottom-Top LOOK Approach):\n");

// Find the position of the head in the sorted array


int start_index = 0;
for (i = 0; i < n; i++)
{
if (sorted_requests[i] >= head)
{
start_index = i;
break;
}
}
// Move Downwards (Bottom-Up)
for (i = start_index - 1; i >= 0; i--)
{
printf("%d -> %d\n", head, sorted_requests[i]);
total_head_movement += abs(sorted_requests[i] - head);
head = sorted_requests[i];
}
// After reaching the lowest request, reverse direction
for (i = start_index; i < n; i++)
{
printf("%d -> %d\n", head, sorted_requests[i]);
total_head_movement += abs(sorted_requests[i] - head);
head = sorted_requests[i];
}
// Display the total head movement
printf("Total Distance Covered in Tracks (Bottom-Top LOOK): %d\n",
total_head_movement);
}
int main()
{
// Self-initialized values for disk requests and head position
int requests[] = {95, 180, 34, 119, 11, 123, 62, 64}; // Disk request queue
int n = sizeof(requests) / sizeof(requests[0]); // Number of disk requests
int head = 50;

// Run LOOK Disk Scheduling Algorithm (Top-Bottom approach)


LOOK_Top_Bottom(requests, n, head);

// Run LOOK Disk Scheduling Algorithm (Bottom-Top approach)


LOOK_Bottom_Top(requests, n, head);
return 0;
}
OUTPUT:

C-LOOK Disk Scheduling Algorithm

SOURCE CODE:
#include <stdio.h>
#include <stdlib.h>
void C_LOOK_Top_Bottom(int requests[], int n, int head)
{
int total_head_movement = 0;
int sorted_requests[n]; // Array to store sorted requests
int i, j;

// Copy the requests


for (i = 0; i < n; i++)
sorted_requests[i] = requests[i];
// Sort the request array
for (i = 0; i < n; i++)
{
for (j = i + 1; j < n; j++)
{
if (sorted_requests[i] > sorted_requests[j])
{
int temp = sorted_requests[i];
sorted_requests[i] = sorted_requests[j];
sorted_requests[j] = temp;
}
}
}
// Display the initial head position
printf("Initial Head Position: %d\n", head);
printf("Disk Head Movement Sequence (Top-Bottom C-LOOK Approach):\n");

// Find the position of the head in the sorted array


int start_index = 0;
for (i = 0; i < n; i++)
{
if (sorted_requests[i] >= head)
{
start_index = i;
break;
}
}
// Move Upwards (Top-Down)
for (i = start_index; i < n; i++)
{
printf("%d -> %d\n", head, sorted_requests[i]);
total_head_movement += abs(sorted_requests[i] - head);
head = sorted_requests[i];
}
// Jump directly to the lowest unserviced request
if (start_index > 0)
{
printf("%d -> %d (Jump)\n", head, sorted_requests[0]);
total_head_movement += abs(head - sorted_requests[0]);
head = sorted_requests[0];

// Move Upwards again from the lowest request


for (i = 0; i < start_index; i++)
{
printf("%d -> %d\n", head, sorted_requests[i]);
total_head_movement += abs(sorted_requests[i] - head);
head = sorted_requests[i];
}
}
// Display the total head movement
printf("Total Distance Covered in Tracks (Top-Bottom C-LOOK): %d\n",
total_head_movement);
}
void C_LOOK_Bottom_Top(int requests[], int n, int head)
{
int total_head_movement = 0;
int sorted_requests[n]; // Array to store sorted requests
int i, j;

// Copy the requests


for (i = 0; i < n; i++)
sorted_requests[i] = requests[i];

// Sort the request array


for (i = 0; i < n; i++)
{
for (j = i + 1; j < n; j++)
{
if (sorted_requests[i] > sorted_requests[j])
{
int temp = sorted_requests[i];
sorted_requests[i] = sorted_requests[j];
sorted_requests[j] = temp;
}
}
}
// Display the initial head position
printf("\nInitial Head Position: %d\n", head);
printf("Disk Head Movement Sequence (Bottom-Top C-LOOK Approach):\n");

// Find the position of the head in the sorted array


int start_index = 0;
for (i = 0; i < n; i++)
{
if (sorted_requests[i] >= head)
{
start_index = i;
break;
}
}
// Move Downwards (Bottom-Up)
for (i = start_index - 1; i >= 0; i--)
{
printf("%d -> %d\n", head, sorted_requests[i]);
total_head_movement += abs(sorted_requests[i] - head);
head = sorted_requests[i];
}

// Jump directly to the highest unserviced request


if (start_index < n)
{
printf("%d -> %d (Jump)\n", head, sorted_requests[n - 1]);
total_head_movement += abs(head - sorted_requests[n - 1]);
head = sorted_requests[n - 1];

// Move Downwards again from the highest request


for (i = n - 2; i >= start_index; i--)
{
printf("%d -> %d\n", head, sorted_requests[i]);
total_head_movement += abs(sorted_requests[i] - head);
head = sorted_requests[i];
}
}
// Display the total head movement
printf("Total Distance Covered in Tracks (Bottom-Top C-LOOK): %d\n",
total_head_movement);
}
int main()
{
// Self-initialized values for disk requests and head position
int requests[] = {95, 180, 34, 119, 11, 123, 62, 64}; // Disk request queue
int n = sizeof(requests) / sizeof(requests[0]); // Number of disk requests
int head = 50;

// Run C-LOOK Disk Scheduling Algorithm (Top-Bottom approach)


C_LOOK_Top_Bottom(requests, n, head);

// Run C-LOOK Disk Scheduling Algorithm (Bottom-Top approach)


C_LOOK_Bottom_Top(requests, n, head);
return 0;
}

OUTPUT:

RESULT AND CONCLUSION:


In this lab, we demonstrated our comprehension of disk scheduling algorithms by crafting a
program to calculate total movement of R/W head of the disk through the implementation of
various C programming library files.
TITLE: CASE STUDY OF LINUX OPERATING SYSTEM.

OBJECTIVE:
i) To learn about the architecture, features, and functionalities of the Linux operating
system and its applications in real-world scenarios.

THEORY:
Linux is an open-source, Unix-like operating system widely used in servers, desktops, mobile
devices, and embedded systems. Its modular architecture comprises a monolithic kernel
responsible for managing hardware resources, process scheduling, and memory management.
Linux supports multitasking, multiuser operations, and file system management, offering
flexibility and efficiency.
Key features include support for multiple file systems (ext4, XFS, FAT), robust security
through permissions and SELinux, and dynamic library linking for efficient application
execution.Linux distributions such as Ubuntu, CentOS, and Debian cater to diverse use cases,
from general-purpose computing to enterprise-level servers. The OS is extensively used in
cloud computing, containerization (via Docker), and high-performance computing clusters
due to its scalability and reliability.
Its package management systems (like apt, yum) simplify software installation and updates.
A notable example is its role in powering the majority of web servers, including those for
companies like Google and Facebook, emphasizing its stability and performance. This case
study highlights Linux's versatility and dominance in modern computing environments.

You might also like