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

Lab Manual 21bce11136

Uploaded by

imim20033002
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
26 views

Lab Manual 21bce11136

Uploaded by

imim20033002
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 80

study of hardware and software requirements of various operating system.

(UNIX, LINUX,
WINDOWSXP, WINDOWS7/8)

1. UNIX:

 Hardware Requirements: UNIX systems have varied hardware requirements


depending on the specific distribution. UNIX-like operating systems such as Solaris,
HP-UX, and AIX are often used on server-grade hardware with multi-core processors,
ample RAM, and high-speed storage systems. For desktop use, hardware
requirements may be similar to Linux distributions.

 Software Requirements: UNIX typically requires a compatible UNIX-like kernel and


supporting utilities. Additionally, specific UNIX distributions may have their own
software requirements and dependencies.

2. Linux:

 Hardware Requirements: Linux distributions have a wide range of hardware


support, from lightweight distributions suitable for older hardware to enterprise-
grade distributions optimized for server deployments. Generally, Linux can run on a
variety of hardware configurations, including x86, x64, ARM, and more.

 Software Requirements: Linux requires a compatible kernel and userland utilities.


Additionally, specific distributions may have additional software requirements
depending on their intended use case and installed packages.

3. Windows XP:

 Hardware Requirements: Windows XP was released in 2001, so its hardware


requirements are relatively modest by modern standards. It typically requires a
Pentium 233 MHz processor or higher, 64 MB RAM (128 MB recommended), and 1.5
GB of available hard disk space. However, for better performance, higher
specifications are recommended.

 Software Requirements: Windows XP comes with its own software suite, including
system utilities, drivers, and optional components. It's compatible with a wide range
of applications designed for the Windows platform.

4. Windows 7/8:

 Hardware Requirements: Windows 7 and 8 have higher hardware requirements


compared to Windows XP. Windows 7 typically requires a 1 GHz processor or faster,
1 GB RAM (2 GB for 64-bit), and 16 GB of available hard disk space (20 GB for 64-bit).
Windows 8 has similar requirements.

 Software Requirements: Windows 7 and 8 come with their own software suite and
are compatible with a wide range of applications designed for the Windows
platform. They also include additional features and enhancements over Windows
XP.

UNIX system calls for process management

1. fork():
 Creates a new process by duplicating the calling process. The new process is called
the child process, and the original process is the parent process.

#include <stdio.h>

#include <unistd.h>

int main() {

pid_t pid;

// Fork a child process

pid = fork();

// Check if fork was successful

if (pid < 0) {

// Error occurred

fprintf(stderr, "Fork failed.\n");

return 1;

} else if (pid == 0) {

// Child process

printf("This is the child process. PID: %d\n", getpid());

} else {

// Parent process

printf("This is the parent process. Child PID: %d\n", pid);

return 0;

2. exec():
 Replaces the current process image with a new process image. There are several
variants of the exec() system call, such as execve(), execl(), execv(), etc., each taking
different arguments and providing different ways to execute a new program.

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

int main() {

// Executing ls command

execl("/bin/ls", "ls", "-l", NULL);

// If execl returns, it indicates an error

perror("exec");

return 1;

3. wait():

 Suspends the execution of the calling process until one of its child processes
terminates. It allows the parent process to wait for the completion of the child
process.

#include <stdio.h>

#include <stdlib.h>

#include <sys/wait.h>

#include <unistd.h>

int main() {

pid_t pid;

// Fork a child process

pid = fork();
if (pid < 0) {

// Error occurred

perror("Fork failed");

exit(EXIT_FAILURE);

} else if (pid == 0) {

// Child process

printf("Child process executing...\n");

sleep(2); // Simulate some work in the child process

printf("Child process exiting...\n");

exit(EXIT_SUCCESS);

} else {

// Parent process

printf("Parent process waiting for child to finish...\n");

int status;

wait(&status); // Wait for child process to finish

if (WIFEXITED(status)) {

printf("Child process exited with status: %d\n", WEXITSTATUS(status));

} else {

printf("Child process exited abnormally\n");

printf("Parent process exiting...\n");

exit(EXIT_SUCCESS);

4. waitpid():

 Similar to wait(), but it allows the parent process to wait for a specific child process
to terminate, specified by its process ID (PID).

#include <stdio.h>

#include <stdlib.h>
#include <sys/wait.h>

#include <unistd.h>

int main() {

pid_t pid, child_pid;

int status;

// Fork a child process

pid = fork();

if (pid < 0) {

// Error occurred

perror("Fork failed");

exit(EXIT_FAILURE);

} else if (pid == 0) {

// Child process

printf("Child process executing...\n");

sleep(2); // Simulate some work in the child process

printf("Child process exiting...\n");

exit(EXIT_SUCCESS);

} else {

// Parent process

printf("Parent process waiting for child to finish...\n");

// Wait for the specific child process with pid

child_pid = waitpid(pid, &status, 0);

if (child_pid == -1) {

perror("waitpid");

exit(EXIT_FAILURE);

if (WIFEXITED(status)) {
printf("Child process with PID %d exited with status: %d\n", child_pid,
WEXITSTATUS(status));

} else {

printf("Child process with PID %d exited abnormally\n", child_pid);

printf("Parent process exiting...\n");

exit(EXIT_SUCCESS);

5. exit():

 Terminates the calling process and returns an exit status to the parent process.

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

int main() {

printf("This is before calling exit()\n");

// Calling exit() to terminate the process

exit(0);

// This line will not be executed

printf("This is after calling exit()\n");

return 0;

6. getpid():

 Returns the process ID of the calling process.

#include <stdio.h>

#include <unistd.h>

int main() {
// Get the process ID of the current process

pid_t pid = getpid();

// Print the process ID

printf("Process ID: %d\n", pid);

return 0;

7. getppid():

 Returns the parent process ID of the calling process.

#include <stdio.h>

#include <unistd.h>

int main() {

// Get the parent process ID of the current process

pid_t parent_pid = getppid();

// Print the parent process ID

printf("Parent Process ID: %d\n", parent_pid);

return 0;

}
8. kill():

 Sends a signal to a process or a group of processes. Signals can be used for various
purposes, such as terminating a process (SIGKILL) or requesting it to terminate
gracefully (SIGTERM).

#include <stdio.h>

#include <stdlib.h>

#include <signal.h>

#include <unistd.h>

int main() {

pid_t pid = getpid(); // Get the PID of the current process

// Print the PID of the current process

printf("Process ID: %d\n", pid);

// Send SIGTERM signal to the current process

int result = kill(pid, SIGTERM);

// Check if kill was successful

if (result == 0) {

printf("SIGTERM signal sent successfully to process %d\n", pid);

} else {

perror("kill");

exit(EXIT_FAILURE);

return 0;

9. signal():

 Sets a signal handler for a specific signal. Signal handlers define how a process
should react when it receives a particular signal.
#include <stdio.h>

#include <stdlib.h>

#include <signal.h>

#include <unistd.h>

// Signal handler function

void sigint_handler(int signum) {

printf("Caught SIGINT signal (%d)\n", signum);

exit(EXIT_SUCCESS);

int main() {

// Install signal handler for SIGINT (Ctrl+C)

signal(SIGINT, sigint_handler);

printf("Press Ctrl+C to send SIGINT signal...\n");

// Infinite loop to keep the program running

while (1) {

sleep(1); // Sleep for 1 second

return 0;

10. nice():

 Changes the priority of a process. It allows a process to voluntarily lower its priority
to give more CPU time to other processes.

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>
int main() {

int priority;

// Get the current process's nice value

priority = nice(0);

if (priority == -1) {

perror("nice");

exit(EXIT_FAILURE);

printf("Current nice value: %d\n", priority);

// Set a new nice value for the current process

int new_priority = nice(10);

if (new_priority == -1) {

perror("nice");

exit(EXIT_FAILURE);

printf("New nice value set to: %d\n", new_priority);

return 0;

UNIX system calls for file management

1. open():

 Opens or creates a file and returns a file descriptor for further operations.

 Syntax: int open(const char *pathname, int flags, mode_t mode);

#include <stdio.h>

#include <stdlib.h>

#include <fcntl.h>

#include <unistd.h>

int main() {
int fd;

// Open a file in read-only mode

fd = open("example.txt", O_RDONLY);

if (fd == -1) {

perror("open");

exit(EXIT_FAILURE);

printf("File opened successfully with file descriptor: %d\n", fd);

// Close the file

if (close(fd) == -1) {

perror("close");

exit(EXIT_FAILURE);

printf("File closed successfully\n");

return 0;

2. close():

 Closes a file descriptor, releasing associated resources.

 Syntax: int close(int fd);

#include <stdio.h>

#include <stdlib.h>

#include <fcntl.h>

#include <unistd.h>

int main() {

int fd;
// Open a file in read-only mode

fd = open("example.txt", O_RDONLY);

if (fd == -1) {

perror("open");

exit(EXIT_FAILURE);

printf("File opened successfully with file descriptor: %d\n", fd);

// Close the file

if (close(fd) == -1) {

perror("close");

exit(EXIT_FAILURE);

printf("File closed successfully\n");

return 0;

3. read():

 Reads data from a file descriptor into a buffer.

 Syntax: ssize_t read(int fd, void *buf, size_t count);

#include <stdio.h>

#include <stdlib.h>

#include <fcntl.h>

#include <unistd.h>

#define BUFFER_SIZE 1024

int main() {
int fd;

ssize_t bytes_read;

char buffer[BUFFER_SIZE + 1]; // +1 for null terminator

// Open a file in read-only mode

fd = open("example.txt", O_RDONLY);

if (fd == -1) {

perror("open");

exit(EXIT_FAILURE);

printf("File opened successfully\n");

// Read from the file

bytes_read = read(fd, buffer, BUFFER_SIZE);

if (bytes_read == -1) {

perror("read");

exit(EXIT_FAILURE);

// Null-terminate the buffer

buffer[bytes_read] = '\0';

printf("Bytes read from file: %zd\n", bytes_read);

printf("Data read from file:\n%s\n", buffer);

// Close the file

if (close(fd) == -1) {

perror("close");

exit(EXIT_FAILURE);

}
printf("File closed successfully\n");

return 0;

4. write():

 Writes data from a buffer to a file descriptor.

 Syntax: ssize_t write(int fd, const void *buf, size_t count);

#include <stdio.h>

#include <stdlib.h>

#include <fcntl.h>

#include <unistd.h>

int main() {

int fd;

ssize_t bytes_written;

char *data = "Hello, world!\n";

// Open a file in write-only mode, creating it if it doesn't exist

fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);

if (fd == -1) {

perror("open");

exit(EXIT_FAILURE);

printf("File opened successfully\n");

// Write data to the file

bytes_written = write(fd, data, strlen(data));

if (bytes_written == -1) {

perror("write");
exit(EXIT_FAILURE);

printf("Bytes written to file: %zd\n", bytes_written);

// Close the file

if (close(fd) == -1) {

perror("close");

exit(EXIT_FAILURE);

printf("File closed successfully\n");

return 0;

5. lseek():

 Repositions the offset of the file descriptor.

 Syntax: off_t lseek(int fd, off_t offset, int whence);

#include <stdio.h>

#include <stdlib.h>

#include <fcntl.h>

#include <unistd.h>

int main() {

int fd;

off_t offset;

// Open a file in read-write mode

fd = open("example.txt", O_RDWR);

if (fd == -1) {

perror("open");
exit(EXIT_FAILURE);

// Seek to the beginning of the file

offset = lseek(fd, 0, SEEK_SET);

if (offset == -1) {

perror("lseek");

exit(EXIT_FAILURE);

printf("File offset after seeking: %ld\n", (long) offset);

// Close the file

if (close(fd) == -1) {

perror("close");

exit(EXIT_FAILURE);

return 0;

6. unlink():

 Deletes a name from the file system. If that name was the last link to the file and no
processes have it open, the file is deleted.

 Syntax: int unlink(const char *pathname);

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

int main() {

// Path to the file to be deleted

const char *filename = "example.txt";


// Attempt to delete the file

if (unlink(filename) == -1) {

perror("unlink");

exit(EXIT_FAILURE);

printf("File '%s' deleted successfully\n", filename);

return 0;

7. rename():

 Renames a file, moving it between directories if required.

 Syntax: int rename(const char *oldpath, const char *newpath);

#include <stdio.h>

#include <stdlib.h>

int main() {

const char *old_filename = "old_name.txt";

const char *new_filename = "new_name.txt";

// Attempt to rename the file

if (rename(old_filename, new_filename) == -1) {

perror("rename");

exit(EXIT_FAILURE);

printf("File '%s' renamed to '%s' successfully\n", old_filename, new_filename);

return 0;

}
8. mkdir():

 Creates a new directory.

 Syntax: int mkdir(const char *pathname, mode_t mode);

#include <stdio.h>

#include <stdlib.h>

#include <sys/stat.h>

#include <sys/types.h>

int main() {

const char *dirname = "new_directory";

// Attempt to create the directory

if (mkdir(dirname, 0777) == -1) {

perror("mkdir");

exit(EXIT_FAILURE);

printf("Directory '%s' created successfully\n", dirname);

return 0;

9. rmdir():

 Deletes a directory.

 Syntax: int rmdir(const char *pathname);

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

int main() {

const char *dirname = "directory_to_remove";


// Attempt to remove the directory

if (rmdir(dirname) == -1) {

perror("rmdir");

exit(EXIT_FAILURE);

printf("Directory '%s' removed successfully\n", dirname);

return 0;

10. stat() and fstat():

 Retrieves information about a file (e.g., file size, permissions, modification time).

 Syntax: int stat(const char *pathname, struct stat *buf); and int fstat(int fd, struct
stat *buf);

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>

#include <fcntl.h>

int main() {

const char *filename = "example.txt";

struct stat file_info;

// Use stat() to get information about a file by filename

if (stat(filename, &file_info) == -1) {

perror("stat");

exit(EXIT_FAILURE);

}
printf("Information about file '%s':\n", filename);

printf("File size: %ld bytes\n", file_info.st_size);

printf("File permissions: %o\n", file_info.st_mode & 0777);

printf("File inode number: %ld\n", (long) file_info.st_ino);

// Open the file to obtain a file descriptor

int fd = open(filename, O_RDONLY);

if (fd == -1) {

perror("open");

exit(EXIT_FAILURE);

// Use fstat() to get information about a file by file descriptor

struct stat fd_info;

if (fstat(fd, &fd_info) == -1) {

perror("fstat");

exit(EXIT_FAILURE);

printf("\nInformation about file '%s' obtained using file descriptor:\n", filename);

printf("File size: %ld bytes\n", fd_info.st_size);

printf("File permissions: %o\n", fd_info.st_mode & 0777);

printf("File inode number: %ld\n", (long) fd_info.st_ino);

// Close the file

if (close(fd) == -1) {

perror("close");

exit(EXIT_FAILURE);

return 0;
}

11. chmod():

 Changes the permissions of a file.

 Syntax: int chmod(const char *pathname, mode_t mode);

#include <stdio.h>

#include <stdlib.h>

#include <sys/stat.h>

int main() {

const char *filename = "example.txt";

mode_t new_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // Readable by


owner, writable by owner, readable by group, readable by others

// Attempt to change the permissions of the file

if (chmod(filename, new_mode) == -1) {

perror("chmod");

exit(EXIT_FAILURE);

printf("Permissions of file '%s' changed successfully\n", filename);

return 0;

12. chown():

 Changes the owner and group of a file.

 Syntax: int chown(const char *pathname, uid_t owner, gid_t group);

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

int main() {
const char *filename = "example.txt";

uid_t new_owner = 1000; // UID of the new owner

gid_t new_group = 1000; // GID of the new group

// Attempt to change the ownership of the file

if (chown(filename, new_owner, new_group) == -1) {

perror("chown");

exit(EXIT_FAILURE);

printf("Ownership of file '%s' changed successfully\n", filename);

return 0;

UNIX system calls for input/output system calls

1. open():

 Opens or creates a file and returns a file descriptor for further operations.

 Syntax: int open(const char *pathname, int flags, mode_t mode);

2. close():

 Closes a file descriptor, releasing associated resources.

 Syntax: int close(int fd);

3. read():

 Reads data from a file descriptor into a buffer.

 Syntax: ssize_t read(int fd, void *buf, size_t count);

4. write():

 Writes data from a buffer to a file descriptor.

 Syntax: ssize_t write(int fd, const void *buf, size_t count);

5. lseek():

 Repositions the offset of the file descriptor.

 Syntax: off_t lseek(int fd, off_t offset, int whence);

6. dup() and dup2():


 Duplicates an existing file descriptor.

 Syntax: int dup(int oldfd); and int dup2(int oldfd, int newfd);

 For dup()

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <fcntl.h>

int main() {

int fd, new_fd;

// Open a file for reading

fd = open("example.txt", O_RDONLY);

if (fd == -1) {

perror("open");

exit(EXIT_FAILURE);

// Duplicate the file descriptor

new_fd = dup(fd);

if (new_fd == -1) {

perror("dup");

exit(EXIT_FAILURE);

printf("Original file descriptor: %d\n", fd);

printf("New file descriptor (duplicated): %d\n", new_fd);

// Close the original file descriptor

if (close(fd) == -1) {

perror("close");
exit(EXIT_FAILURE);

// Close the duplicated file descriptor

if (close(new_fd) == -1) {

perror("close");

exit(EXIT_FAILURE);

return 0;

For dup2()

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <fcntl.h>

int main() {

int fd, new_fd;

// Open a file for reading

fd = open("example.txt", O_RDONLY);

if (fd == -1) {

perror("open");

exit(EXIT_FAILURE);

// Duplicate the file descriptor

new_fd = dup2(fd, 100); // Duplicate to a specific file descriptor (100 in this case)

if (new_fd == -1) {

perror("dup2");
exit(EXIT_FAILURE);

printf("Original file descriptor: %d\n", fd);

printf("New file descriptor (duplicated): %d\n", new_fd);

// Close the original file descriptor

if (close(fd) == -1) {

perror("close");

exit(EXIT_FAILURE);

// No need to close the duplicated file descriptor (new_fd) as it's duplicated to a


specific file descriptor

return 0;

7. pipe():

 Creates an interprocess communication pipe.

 Syntax: int pipe(int pipefd[2]);

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

int main() {

int pipefd[2];

char buffer[256];

ssize_t bytes_read;

// Create a pipe

if (pipe(pipefd) == -1) {
perror("pipe");

exit(EXIT_FAILURE);

// Fork a child process

pid_t pid = fork();

if (pid == -1) {

perror("fork");

exit(EXIT_FAILURE);

} else if (pid == 0) { // Child process

// Close the write end of the pipe

close(pipefd[1]);

// Read from the pipe

bytes_read = read(pipefd[0], buffer, sizeof(buffer));

if (bytes_read == -1) {

perror("read");

exit(EXIT_FAILURE);

printf("Child process received message from parent: %s\n", buffer);

// Close the read end of the pipe

close(pipefd[0]);

exit(EXIT_SUCCESS);

} else { // Parent process

// Close the read end of the pipe

close(pipefd[0]);
// Write to the pipe

const char *message = "Hello from parent!";

if (write(pipefd[1], message, sizeof(message)) == -1) {

perror("write");

exit(EXIT_FAILURE);

printf("Parent process sent message to child: %s\n", message);

// Close the write end of the pipe

close(pipefd[1]);

return 0;

8. ioctl():

 Performs device-specific I/O operations.

 Syntax: int ioctl(int fd, unsigned long request, ...);

#include <stdio.h>

#include <stdlib.h>

#include <fcntl.h>

#include <sys/ioctl.h>

#include <errno.h>

int main() {

int fd;

char device[] = "/dev/tty";

// Open the terminal device

fd = open(device, O_RDWR);

if (fd == -1) {
perror("open");

exit(EXIT_FAILURE);

// Get the terminal size

struct winsize ws;

if (ioctl(fd, TIOCGWINSZ, &ws) == -1) {

perror("ioctl");

close(fd);

exit(EXIT_FAILURE);

printf("Terminal width: %d\n", ws.ws_col);

printf("Terminal height: %d\n", ws.ws_row);

// Close the file descriptor

if (close(fd) == -1) {

perror("close");

exit(EXIT_FAILURE);

return 0;

9. fcntl():

 Performs various operations on file descriptors.

 Syntax: int fcntl(int fd, int cmd, ...);

#include <stdio.h>

#include <stdlib.h>

#include <fcntl.h>

#include <unistd.h>
int main() {

int fd, new_fd;

// Open a file for reading

fd = open("example.txt", O_RDONLY);

if (fd == -1) {

perror("open");

exit(EXIT_FAILURE);

// Duplicate the file descriptor

new_fd = fcntl(fd, F_DUPFD, 0);

if (new_fd == -1) {

perror("fcntl");

exit(EXIT_FAILURE);

printf("Original file descriptor: %d\n", fd);

printf("New file descriptor (duplicated): %d\n", new_fd);

// Close the original file descriptor

if (close(fd) == -1) {

perror("close");

exit(EXIT_FAILURE);

// Close the duplicated file descriptor

if (close(new_fd) == -1) {

perror("close");

exit(EXIT_FAILURE);

}
return 0;

10. select(), poll(), and epoll():

 Multiplexes I/O operations on multiple file descriptors.

 Syntax: int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout); for select(), int poll(struct pollfd *fds, nfds_t nfds, int
timeout); for poll(), and int epoll_wait(int epfd, struct epoll_event *events, int
maxevents, int timeout); for epoll().

 For select()

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/time.h>

#include <sys/types.h>

#include <sys/select.h>

int main() {

fd_set read_fds;

int max_fd, activity, client_socket[5] = {0}; // Sample client sockets

char buffer[1024] = {0};

// Initialize client sockets (sample)

// ...

while (1) {

// Clear the file descriptor set

FD_ZERO(&read_fds);

// Add client sockets to the set

max_fd = -1;

for (int i = 0; i < 5; ++i) { // Assuming 5 client sockets


if (client_socket[i] > 0) {

FD_SET(client_socket[i], &read_fds);

if (client_socket[i] > max_fd)

max_fd = client_socket[i];

// Set timeout

struct timeval timeout;

timeout.tv_sec = 5;

timeout.tv_usec = 0;

// Call select

activity = select(max_fd + 1, &read_fds, NULL, NULL, &timeout);

if (activity < 0) {

perror("select");

exit(EXIT_FAILURE);

// Check for activity

if (activity == 0) {

printf("Timeout occurred\n");

continue;

// Handle activity on sockets

for (int i = 0; i < 5; ++i) { // Assuming 5 client sockets

if (FD_ISSET(client_socket[i], &read_fds)) {

// Read data from the socket

ssize_t bytes_read = read(client_socket[i], buffer, sizeof(buffer));

if (bytes_read == -1) {
perror("read");

// Handle read error

} else if (bytes_read == 0) {

printf("Socket %d disconnected\n", client_socket[i]);

// Close socket and remove from set

close(client_socket[i]);

client_socket[i] = 0;

} else {

printf("Data received from socket %d: %s\n", client_socket[i], buffer);

// Process data

return 0;

For poll()

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <poll.h>

int main() {

struct pollfd fds[5]; // Sample file descriptors

char buffer[1024] = {0};

// Initialize file descriptors (sample)

// ...

while (1) {
// Set up file descriptors for polling

for (int i = 0; i < 5; ++i) { // Assuming 5 file descriptors

fds[i].fd = ...; // Set file descriptor

fds[i].events = POLLIN; // Set events to poll for (e.g., POLLIN for input)

fds[i].revents = 0; // Clear revents

// Call poll

int activity = poll(fds, 5, 5000); // Timeout of 5000 milliseconds (5 seconds)

if (activity == -1) {

perror("poll");

exit(EXIT_FAILURE);

} else if (activity == 0) {

printf("Timeout occurred\n");

continue;

// Check for activity on file descriptors

for (int i = 0; i < 5; ++i) { // Assuming 5 file descriptors

if (fds[i].revents & POLLIN) {

// Read data from the file descriptor

ssize_t bytes_read = read(fds[i].fd, buffer, sizeof(buffer));

if (bytes_read == -1) {

perror("read");

// Handle read error

} else if (bytes_read == 0) {

printf("File descriptor %d disconnected\n", fds[i].fd);

// Handle disconnection

} else {

printf("Data received from file descriptor %d: %s\n", fds[i].fd, buffer);

// Process data
}

return 0;

For epoll()

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/epoll.h>

int main() {

int epoll_fd, num_events;

struct epoll_event event, events[5]; // Sample events

char buffer[1024] = {0};

// Initialize events and create epoll instance (sample)

// ...

while (1) {

// Wait for events

num_events = epoll_wait(epoll_fd, events, 5, 5000); // Timeout of 5000


milliseconds (5 seconds)

if (num_events == -1) {

perror("epoll_wait");

exit(EXIT_FAILURE);

} else if (num_events == 0) {

printf("Timeout occurred\n");

continue;
}

// Handle events

for (int i = 0; i < num_events; ++i) {

if (events[i].events & EPOLLIN) {

// Read data from the file descriptor associated with the event

ssize_t bytes_read = read(events[i].data.fd, buffer, sizeof(buffer));

if (bytes_read == -1) {

perror("read");

// Handle read error

} else if (bytes_read == 0) {

printf("File descriptor %d disconnected\n", events[i].data.fd);

// Handle disconnection

} else {

printf("Data received from file descriptor %d: %s\n", events[i].data.fd,


buffer);

// Process data

return 0;

}
Lab Assessment – 2
FCFS - First Come First Serve
#include <stdio.h>

#include <stdlib.h>

#define MAX_PROCESSES 10

// Process structure

typedef struct {

int id; // Process ID

int burst_time; // CPU burst time

int arrival_time; // Arrival time of the process

int waiting_time; // Waiting time of the process

int turnaround_time;// Turnaround time of the process

} Process;

// Function to calculate waiting time and turnaround time for FCFS

void calculate_fcfs_times(Process processes[], int n) {

processes[0].waiting_time = 0;

processes[0].turnaround_time = processes[0].burst_time;

for (int i = 1; i < n; i++) {

processes[i].waiting_time = processes[i - 1].waiting_time + processes[i - 1].burst_time;

processes[i].turnaround_time = processes[i].waiting_time + processes[i].burst_time;

// Function to display process details for FCFS

void display_fcfs_processes(Process processes[], int n) {

printf("Process\tBurst Time\tArrival Time\tWaiting Time\tTurnaround Time\n");

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

printf("%d\t%d\t\t%d\t\t%d\t\t%d\n", processes[i].id, processes[i].burst_time,

processes[i].arrival_time, processes[i].waiting_time,

processes[i].turnaround_time);

}
int main() {

int n; // Number of processes

Process processes[MAX_PROCESSES]; // Array of processes

printf("Enter the number of processes (up to %d): ", MAX_PROCESSES);

scanf("%d", &n);

// Input process details

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

processes[i].id = i + 1;

printf("Enter CPU burst time for process %d: ", i + 1);

scanf("%d", &processes[i].burst_time);

printf("Enter arrival time for process %d: ", i + 1);

scanf("%d", &processes[i].arrival_time);

// Calculate waiting time and turnaround time for FCFS

calculate_fcfs_times(processes, n);

// Display FCFS scheduling results

printf("\nFCFS Scheduling:\n");

display_fcfs_processes(processes, n);

return 0;

Input
Output

SJF – Shortest Job First


#include <stdio.h>

#include <stdlib.h>

#define MAX_PROCESSES 10

// Process structure

typedef struct {

int id; // Process ID

int burst_time; // CPU burst time

int arrival_time; // Arrival time of the process

int waiting_time; // Waiting time of the process

int turnaround_time;// Turnaround time of the process

} Process;

// Function to sort processes by burst time (SJF)

void sort_by_burst_time(Process processes[], int n) {

// Implement any sorting algorithm here (e.g., Bubble Sort)

// For simplicity, let's use Bubble Sort

for (int i = 0; i < n - 1; i++) {

for (int j = 0; j < n - i - 1; j++) {

if (processes[j].burst_time > processes[j + 1].burst_time) {

// Swap processes

Process temp = processes[j];

processes[j] = processes[j + 1];

processes[j + 1] = temp;

}
}

// Function to calculate waiting time and turnaround time for SJF

void calculate_sjf_times(Process processes[], int n) {

processes[0].waiting_time = 0;

processes[0].turnaround_time = processes[0].burst_time;

for (int i = 1; i < n; i++) {

processes[i].waiting_time = processes[i - 1].waiting_time + processes[i - 1].burst_time;

processes[i].turnaround_time = processes[i].waiting_time + processes[i].burst_time;

// Function to display process details for SJF

void display_sjf_processes(Process processes[], int n) {

printf("Process\tBurst Time\tArrival Time\tWaiting Time\tTurnaround Time\n");

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

printf("%d\t%d\t\t%d\t\t%d\t\t%d\n", processes[i].id, processes[i].burst_time,

processes[i].arrival_time, processes[i].waiting_time,

processes[i].turnaround_time);

int main() {

int n; // Number of processes

Process processes[MAX_PROCESSES]; // Array of processes

printf("Enter the number of processes (up to %d): ", MAX_PROCESSES);

scanf("%d", &n);

// Input process details

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

processes[i].id = i + 1;

printf("Enter CPU burst time for process %d: ", i + 1);


scanf("%d", &processes[i].burst_time);

printf("Enter arrival time for process %d: ", i + 1);

scanf("%d", &processes[i].arrival_time);

// Sort processes based on burst time for SJF

sort_by_burst_time(processes, n);

// Calculate waiting time and turnaround time for SJF

calculate_sjf_times(processes, n);

// Display SJF scheduling results

printf("\nSJF Scheduling:\n");

display_sjf_processes(processes, n);

return 0;

Input

Output

Priority Scheduling
#include <stdio.h>
#include <stdlib.h>

#define MAX_PROCESSES 10

Input

Output

Multi-level Queue
#include <stdio.h>

#include <stdlib.h>

#define MAX_PROCESSES 10

#define NUM_QUEUES 3

// Process structure

typedef struct {

int id; // Process ID

int burst_time; // CPU burst time

int priority; // Priority of the process

int arrival_time; // Arrival time of the process

int waiting_time; // Waiting time of the process


int turnaround_time;// Turnaround time of the process

} Process;

// Function to calculate waiting time and turnaround time for a process

void calculate_times(Process *process) {

process->waiting_time = process->turnaround_time - process->burst_time;

// Function to display process details

void display_processes(Process processes[], int n) {

printf("Process\tBurst Time\tPriority\tArrival Time\tWaiting Time\tTurnaround Time\n");

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

printf("%d\t%d\t\t%d\t\t%d\t\t%d\t\t%d\n", processes[i].id, processes[i].burst_time,

processes[i].priority, processes[i].arrival_time, processes[i].waiting_time,

processes[i].turnaround_time);

int main() {

int n; // Number of processes

Process processes[MAX_PROCESSES]; // Array of processes

Process *queues[NUM_QUEUES][MAX_PROCESSES]; // Multi-level queues

int front[NUM_QUEUES] = {0}; // Front pointer for each queue

int rear[NUM_QUEUES] = {0}; // Rear pointer for each queue

int total_waiting_time = 0; // Total waiting time

int total_turnaround_time = 0; // Total turnaround time

// Initialize queues

for (int i = 0; i < NUM_QUEUES; i++) {

for (int j = 0; j < MAX_PROCESSES; j++) {

queues[i][j] = NULL;

printf("Enter the number of processes (up to %d): ", MAX_PROCESSES);


scanf("%d", &n);

// Input process details

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

processes[i].id = i + 1;

printf("Enter CPU burst time for process %d: ", i + 1);

scanf("%d", &processes[i].burst_time);

printf("Enter priority for process %d: ", i + 1);

scanf("%d", &processes[i].priority);

printf("Enter arrival time for process %d: ", i + 1);

scanf("%d", &processes[i].arrival_time);

// Add process to appropriate queue based on priority

if (processes[i].priority >= 0 && processes[i].priority < NUM_QUEUES) {

queues[processes[i].priority][rear[processes[i].priority]++] = &processes[i];

// Schedule processes from each queue

for (int i = 0; i < NUM_QUEUES; i++) {

for (int j = 0; j < rear[i]; j++) {

// Calculate turnaround time

queues[i][j]->turnaround_time = queues[i][j]->burst_time;

total_turnaround_time += queues[i][j]->turnaround_time;

// Calculate waiting time

if (j > 0) {

queues[i][j]->waiting_time = queues[i][j - 1]->waiting_time + queues[i][j - 1]->burst_time;

total_waiting_time += queues[i][j]->waiting_time;

} else {

queues[i][j]->waiting_time = 0;

}
// Calculate average waiting time and average turnaround time

float avg_waiting_time = (float)total_waiting_time / n;

float avg_turnaround_time = (float)total_turnaround_time / n;

// Display multi-level queue scheduling results

printf("\nMulti-level Queue Scheduling:\n");

display_processes(processes, n);

printf("\nAverage Waiting Time: %.2f\n", avg_waiting_time);

printf("Average Turnaround Time: %.2f\n", avg_turnaround_time);

return 0;

Input

Output
LAB – 3

Implement file storage allocation techniques:

(a) Contiguous (using array)


#include <stdio.h>
#include <stdbool.h>

#define DISK_SIZE 100

char disk[DISK_SIZE]; // Represents the disk


int freeSpace = DISK_SIZE; // Tracks the available free space

// Function to allocate contiguous space for a file


bool allocate(char filename, int size) {
if (size > freeSpace) {
printf("Not enough free space available on disk.\n");
return false;
}

int startIndex = -1; // Start index of contiguous free space


int count = 0; // Count of consecutive free blocks
for (int i = 0; i < DISK_SIZE; ++i) {
if (disk[i] == '\0') { // If block is free
if (startIndex == -1) {
startIndex = i; // Start of a new consecutive free space
}
++count;
if (count == size) { // If required contiguous space is found
for (int j = startIndex; j < startIndex + size; ++j) {
disk[j] = filename; // Allocate space by marking blocks with file name
}
freeSpace -= size; // Update free space count
printf("File '%c' allocated from sector %d to %d.\n", filename, startIndex, startIndex + size -
1);
return true;
}
} else {
startIndex = -1; // Reset startIndex if consecutive free space is broken
count = 0;
}
}

printf("Not enough contiguous free space available on disk.\n");


return false;
}

// Function to deallocate contiguous space allocated for a file


void deallocate(char filename) {
for (int i = 0; i < DISK_SIZE; ++i) {
if (disk[i] == filename) {
disk[i] = '\0'; // Free the block by marking it as available
++freeSpace; // Increment free space count
}
}
printf("File '%c' deallocated.\n", filename);
}

// Function to print disk status


void printDiskStatus() {
printf("Disk Status:\n");
for (int i = 0; i < DISK_SIZE; ++i) {
printf("%c ", disk[i] == '\0' ? '-' : disk[i]);
}
printf("\nFree Space: %d\n", freeSpace);
}

int main() {
// Initialize disk with free space
for (int i = 0; i < DISK_SIZE; ++i) {
disk[i] = '\0';
}

// Example usage
printf("Initial Disk Status:\n");
printDiskStatus();

allocate('A', 5);
allocate('B', 3);
printDiskStatus();

deallocate('A');
printDiskStatus();

allocate('C', 7);
printDiskStatus();

return 0;
}
(b) Linked –list (using linked list)
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

// Define a structure for a disk block


typedef struct DiskBlock {
char data;
struct DiskBlock* next;
} DiskBlock;

DiskBlock* head = NULL; // Head of the linked list representing the disk
int freeSpace = 0; // Tracks the available free space

// Function to allocate space for a file


void allocate(char filename, int size) {
if (size <= freeSpace) {
DiskBlock* newNode;
for (int i = 0; i < size; ++i) {
newNode = (DiskBlock*)malloc(sizeof(DiskBlock));
newNode->data = filename;
newNode->next = head;
head = newNode;
}
freeSpace -= size; // Update free space count
printf("File '%c' allocated using linked list.\n", filename);
} else {
printf("Not enough free space available on disk.\n");
}
}

// Function to deallocate space allocated for a file


void deallocate(char filename) {
DiskBlock *current = head, *prev = NULL;
while (current != NULL) {
if (current->data == filename) {
if (prev != NULL) {
prev->next = current->next;
} else {
head = current->next;
}
free(current);
++freeSpace; // Increment free space count
} else {
prev = current;
}
current = current->next;
}
printf("File '%c' deallocated.\n", filename);
}

// Function to print disk status


void printDiskStatus() {
printf("Disk Status:\n");
DiskBlock* current = head;
while (current != NULL) {
printf("%c -> ", current->data);
current = current->next;
}
printf("NULL\n");
printf("Free Space: %d\n", freeSpace);
}

int main() {
// Initialize free space
freeSpace = 100;

// Example usage
printf("Initial Disk Status:\n");
printDiskStatus();

allocate('A', 5);
allocate('B', 3);
printDiskStatus();

deallocate('A');
printDiskStatus();

allocate('C', 7);
printDiskStatus();

return 0;
}

(c) Indirect allocation (indexing)


#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define DISK_SIZE 100

char disk[DISK_SIZE]; // Represents the disk


int indexBlock[DISK_SIZE]; // Represents the index block
int freeSpace = DISK_SIZE; // Tracks the available free space

// Function to allocate space for a file


void allocate(char filename, int size) {
if (size <= freeSpace) {
int indices[size];
int count = 0;
for (int i = 0; i < DISK_SIZE && count < size; ++i) {
if (disk[i] == '\0') {
indices[count++] = i;
}
}
for (int i = 0; i < size; ++i) {
disk[indices[i]] = filename; // Allocate space by marking blocks with file name
}
indexBlock[filename] = indices[0];
freeSpace -= size; // Update free space count
printf("File '%c' allocated using indirect allocation.\n", filename);
} else {
printf("Not enough free space available on disk.\n");
}
}

// Function to deallocate space allocated for a file


void deallocate(char filename) {
int index = indexBlock[filename];
while (disk[index] != '\0') {
disk[index] = '\0'; // Free the block by marking it as available
++index;
++freeSpace; // Increment free space count
}
printf("File '%c' deallocated.\n", filename);
}

// Function to print disk status


void printDiskStatus() {
printf("Disk Status:\n");
for (int i = 0; i < DISK_SIZE; ++i) {
printf("%c ", disk[i] == '\0' ? '-' : disk[i]);
}
printf("\nFree Space: %d\n", freeSpace);
}
int main() {
// Initialize disk with free space
for (int i = 0; i < DISK_SIZE; ++i) {
disk[i] = '\0';
}

// Example usage
printf("Initial Disk Status:\n");
printDiskStatus();

allocate('A', 5);
allocate('B', 3);
printDiskStatus();

deallocate('A');
printDiskStatus();

allocate('C', 7);
printDiskStatus();

return 0;
}
LAB – 4

Contiguous Allocation Techniques

I. Implementation of Contiguous allocation techniques:


(a) Worst-Fit
(b) Best-Fit
(c) First-Fit

#include <stdio.h>

#define MAX_BLOCKS 100

// Structure to represent a block of memory


struct Block {
int id;
int size;
int allocated;
};

// Function prototypes
void worstFit(struct Block freeBlocks[], int n, int processes[], int m);
void bestFit(struct Block freeBlocks[], int n, int processes[], int m);
void firstFit(struct Block freeBlocks[], int n, int processes[], int m);

int main() {
// Sample data
struct Block freeBlocks[MAX_BLOCKS] = {{1, 100, 0}, {2, 200, 0}, {3, 50, 0}};
int processes[] = {20, 70, 30, 60};

int n = sizeof(freeBlocks) / sizeof(freeBlocks[0]);


int m = sizeof(processes) / sizeof(processes[0]);

printf("Worst Fit Allocation:\n");


worstFit(freeBlocks, n, processes, m);

printf("\nBest Fit Allocation:\n");


bestFit(freeBlocks, n, processes, m);

printf("\nFirst Fit Allocation:\n");


firstFit(freeBlocks, n, processes, m);

return 0;
}

void worstFit(struct Block freeBlocks[], int n, int processes[], int m) {


// Implementation of Worst-Fit allocation
}
void bestFit(struct Block freeBlocks[], int n, int processes[], int m) {
// Implementation of Best-Fit allocation
}

void firstFit(struct Block freeBlocks[], int n, int processes[], int m) {


// Implementation of First-Fit allocation
}
LAB – 5

External and Internal Fragmentation

Calculation of external and internal fragmentation.

#include <stdio.h>

#define MAX_BLOCKS 100

// Structure to represent a block of memory


struct Block {
int id;
int size;
int allocated;
};

// Function prototypes
void calculateFragmentation(struct Block freeBlocks[], int n);

int main() {
// Sample data
struct Block freeBlocks[MAX_BLOCKS] = {{1, 100, 0}, {2, 200, 0}, {3, 50, 0}};
int n = sizeof(freeBlocks) / sizeof(freeBlocks[0]);

calculateFragmentation(freeBlocks, n);

return 0;
}

void calculateFragmentation(struct Block freeBlocks[], int n) {


int externalFragmentation = 0;
int totalFreeSpace = 0;
int totalAllocatedSpace = 0;

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


if (!freeBlocks[i].allocated) {
totalFreeSpace += freeBlocks[i].size;
if (freeBlocks[i].size < 20) { // Example threshold for internal fragmentation
externalFragmentation += freeBlocks[i].size;
}
} else {
totalAllocatedSpace += freeBlocks[i].size;
}
}
int internalFragmentation = totalAllocatedSpace - totalFreeSpace;

printf("Total External Fragmentation: %d\n", externalFragmentation);


printf("Total Internal Fragmentation: %d\n", internalFragmentation);
}
LAB – 6

External and Internal Fragmentation

Implementation of Compaction for the continually changing memory layout and calculate total
movement of data.

#include <stdio.h>

#define MAX_BLOCKS 100

// Structure to represent a block of memory

struct Block {

int id;

int size;

int allocated;

};

// Function prototypes

void compactMemory(struct Block freeBlocks[], int n, int *totalMovement);

void printMemoryLayout(struct Block freeBlocks[], int n);

int main() {

// Sample data

struct Block freeBlocks[MAX_BLOCKS] = {{1, 100, 1}, {2, 200, 0}, {3, 50, 1}};

int n = sizeof(freeBlocks) / sizeof(freeBlocks[0]);

printf("Before Compaction:\n");

printMemoryLayout(freeBlocks, n);

int totalMovement = 0;

compactMemory(freeBlocks, n, &totalMovement);
printf("\nAfter Compaction:\n");

printMemoryLayout(freeBlocks, n);

printf("Total Movement of Data: %d\n", totalMovement);

return 0;

void compactMemory(struct Block freeBlocks[], int n, int *totalMovement) {

int currentPos = 0;

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

if (freeBlocks[i].allocated) {

freeBlocks[i].id = currentPos++;

*totalMovement += abs(freeBlocks[i].id - i);

void printMemoryLayout(struct Block freeBlocks[], int n) {

printf("Block ID\tSize\tAllocated\n");

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

printf("%d\t\t%d\t%d\n", freeBlocks[i].id, freeBlocks[i].size, freeBlocks[i].allocated);

}
LAB – 7

Resource Allocation Graph (RAG)

Implementation of resource allocation graph (RAG).

#include <stdio.h>

#include <stdbool.h>

#define MAX_NODES 100

// Structure to represent a node in the graph

struct Node {

int id;

bool visited;

bool allocated;

};

// Structure to represent an edge in the graph

struct Edge {

int from;

int to;

};

// Function prototypes

void initializeGraph(struct Node nodes[], int n);

void addEdge(struct Edge edges[], int *numEdges, int from, int to);

void printGraph(struct Node nodes[], struct Edge edges[], int n, int numEdges);

bool isCycleUtil(struct Node nodes[], struct Edge edges[], int n, int u);

bool isCycle(struct Node nodes[], struct Edge edges[], int n);

int main() {

struct Node nodes[MAX_NODES];

struct Edge edges[MAX_NODES];


int numNodes = 5; // Number of nodes in the graph

int numEdges = 0; // Number of edges in the graph

// Initialize nodes

initializeGraph(nodes, numNodes);

// Add edges

addEdge(edges, &numEdges, 0, 2);

addEdge(edges, &numEdges, 1, 3);

addEdge(edges, &numEdges, 2, 4);

addEdge(edges, &numEdges, 3, 4);

addEdge(edges, &numEdges, 4, 1);

// Print the graph

printGraph(nodes, edges, numNodes, numEdges);

// Check for cycle

if (isCycle(nodes, edges, numNodes)) {

printf("Cycle detected in the graph.\n");

} else {

printf("No cycle detected in the graph.\n");

return 0;

// Initialize nodes of the graph

void initializeGraph(struct Node nodes[], int n) {

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

nodes[i].id = i;

nodes[i].visited = false;
nodes[i].allocated = false;

// Add an edge to the graph

void addEdge(struct Edge edges[], int *numEdges, int from, int to) {

edges[*numEdges].from = from;

edges[*numEdges].to = to;

(*numEdges)++;

// Print the graph

void printGraph(struct Node nodes[], struct Edge edges[], int n, int numEdges) {

printf("Resource Allocation Graph:\n");

for (int i = 0; i < numEdges; ++i) {

printf("%d -> %d\n", edges[i].from, edges[i].to);

// Utility function to check for cycle recursively

bool isCycleUtil(struct Node nodes[], struct Edge edges[], int n, int u) {

if (!nodes[u].visited) {

nodes[u].visited = true;

nodes[u].allocated = true;

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

if (edges[i].from == u) {

if (!nodes[edges[i].to].visited && isCycleUtil(nodes, edges, n, edges[i].to)) {

return true;

} else if (nodes[edges[i].to].allocated) {

return true;
}

nodes[u].allocated = false;

return false;

// Check for cycle in the graph

bool isCycle(struct Node nodes[], struct Edge edges[], int n) {

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

if (!nodes[i].visited && isCycleUtil(nodes, edges, n, i)) {

return true;

return false;

}
LAB – 8

Bankers Algorithm

Implementation of Banker’s Algorithm.

#include <stdio.h>

#include <stdbool.h>

#define MAX_PROCESSES 100

#define MAX_RESOURCES 100

// Function prototypes

bool isSafeState(int available[], int max[][MAX_RESOURCES], int allocation[][MAX_RESOURCES], int


need[][MAX_RESOURCES], int processes[], int numProcesses, int numResources);

void printSafeSequence(int safeSequence[], int numProcesses);

int main() {

int available[MAX_RESOURCES];

int max[MAX_PROCESSES][MAX_RESOURCES];

int allocation[MAX_PROCESSES][MAX_RESOURCES];

int need[MAX_PROCESSES][MAX_RESOURCES];

int processes[MAX_PROCESSES];

int numProcesses, numResources;

// Input the number of processes and resources

printf("Enter number of processes: ");

scanf("%d", &numProcesses);

printf("Enter number of resources: ");

scanf("%d", &numResources);

// Input available resources

printf("Enter available resources:\n");

for (int i = 0; i < numResources; ++i) {


scanf("%d", &available[i]);

// Input maximum resources required by each process

printf("Enter maximum resources required by each process:\n");

for (int i = 0; i < numProcesses; ++i) {

printf("For process %d: ", i);

for (int j = 0; j < numResources; ++j) {

scanf("%d", &max[i][j]);

processes[i] = i; // Assigning process IDs

// Input allocated resources for each process

printf("Enter allocated resources for each process:\n");

for (int i = 0; i < numProcesses; ++i) {

printf("For process %d: ", i);

for (int j = 0; j < numResources; ++j) {

scanf("%d", &allocation[i][j]);

// Calculate need resources

need[i][j] = max[i][j] - allocation[i][j];

// Run Banker's Algorithm

if (isSafeState(available, max, allocation, need, processes, numProcesses, numResources)) {

printf("Safe state! Safe sequence: ");

printSafeSequence(processes, numProcesses);

} else {

printf("Unsafe state! Deadlock detected.\n");

}
return 0;

// Function to check if system is in safe state using Banker's Algorithm

bool isSafeState(int available[], int max[][MAX_RESOURCES], int allocation[][MAX_RESOURCES], int


need[][MAX_RESOURCES], int processes[], int numProcesses, int numResources) {

bool finish[numProcesses];

int work[MAX_RESOURCES];

int safeSequence[numProcesses];

int count = 0;

// Initialize finish array

for (int i = 0; i < numProcesses; ++i) {

finish[i] = false;

// Initialize work array

for (int i = 0; i < numResources; ++i) {

work[i] = available[i];

// Find a process which can be allocated

while (count < numProcesses) {

bool found = false;

for (int i = 0; i < numProcesses; ++i) {

if (!finish[i]) {

bool canAllocate = true;

for (int j = 0; j < numResources; ++j) {

if (need[i][j] > work[j]) {

canAllocate = false;
break;

if (canAllocate) {

// Process can be allocated

for (int j = 0; j < numResources; ++j) {

work[j] += allocation[i][j];

safeSequence[count++] = i;

finish[i] = true;

found = true;

// If no process found, break loop

if (!found) {

break;

// If all processes are not finished, then unsafe state

if (count != numProcesses) {

return false;

// Safe state

return true;

// Function to print safe sequence

void printSafeSequence(int safeSequence[], int numProcesses) {


for (int i = 0; i < numProcesses; ++i) {

printf("%d ", safeSequence[i]);

printf("\n");

}
LAB – 9

Wait Graph

Conversion of resource allocation graph (RAG) to wait-for-graph (WFG) for each type of method
used for storing graph.

#include <stdio.h>

#include <stdbool.h>

#define MAX_NODES 100

// Structure to represent a node in the graph

struct Node {

int id;

struct Node* next;

};

// Function prototypes

void convertToWaitForGraphAdjList(struct Node* rag[], struct Node* wfg[], int numProcesses);

void convertToWaitForGraphAdjMatrix(bool rag[][MAX_NODES], bool wfg[][MAX_NODES], int


numProcesses);

int main() {

// Sample Resource Allocation Graph (RAG) represented as adjacency list

struct Node* rag[MAX_NODES];

// Initialize RAG adjacency list

for (int i = 0; i < MAX_NODES; ++i) {

rag[i] = NULL;

// Assuming some resource allocation relationships

rag[0] = (struct Node*)malloc(sizeof(struct Node));

rag[0]->id = 1;

rag[0]->next = NULL;

rag[1] = (struct Node*)malloc(sizeof(struct Node));


rag[1]->id = 2;

rag[1]->next = NULL;

rag[2] = (struct Node*)malloc(sizeof(struct Node));

rag[2]->id = 0;

rag[2]->next = NULL;

// Number of processes

int numProcesses = 3;

// Convert RAG to WFG using adjacency list

struct Node* wfg[MAX_NODES];

convertToWaitForGraphAdjList(rag, wfg, numProcesses);

// Print WFG (adjacency list representation)

printf("Wait-For-Graph (Adjacency List Representation):\n");

for (int i = 0; i < numProcesses; ++i) {

printf("Process %d -> ", i);

struct Node* current = wfg[i];

while (current != NULL) {

printf("%d ", current->id);

current = current->next;

printf("\n");

// Convert RAG to WFG using adjacency matrix

bool ragMatrix[MAX_NODES][MAX_NODES] = {false}; // Assuming no relationship initially

bool wfgMatrix[MAX_NODES][MAX_NODES];

for (int i = 0; i < numProcesses; ++i) {

struct Node* current = rag[i];

while (current != NULL) {


ragMatrix[i][current->id] = true;

current = current->next;

// Convert to WFG using adjacency matrix

convertToWaitForGraphAdjMatrix(ragMatrix, wfgMatrix, numProcesses);

// Print WFG (adjacency matrix representation)

printf("\nWait-For-Graph (Adjacency Matrix Representation):\n");

for (int i = 0; i < numProcesses; ++i) {

for (int j = 0; j < numProcesses; ++j) {

printf("%d ", wfgMatrix[i][j]);

printf("\n");

return 0;

// Convert RAG to WFG using adjacency list

void convertToWaitForGraphAdjList(struct Node* rag[], struct Node* wfg[], int numProcesses) {

for (int i = 0; i < numProcesses; ++i) {

wfg[i] = NULL;

for (int j = 0; j < numProcesses; ++j) {

if (i != j) {

struct Node* current = rag[j];

while (current != NULL) {

if (current->id == i) {

// Process i is waiting for process j

struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));

newNode->id = j;
newNode->next = wfg[i];

wfg[i] = newNode;

break;

current = current->next;

// Convert RAG to WFG using adjacency matrix

void convertToWaitForGraphAdjMatrix(bool rag[][MAX_NODES], bool wfg[][MAX_NODES], int


numProcesses) {

for (int i = 0; i < numProcesses; ++i) {

for (int j = 0; j < numProcesses; ++j) {

if (i != j && rag[j][i]) {

// Process i is waiting for process j

wfg[i][j] = true;

} else {

wfg[i][j] = false;

}
LAB – 10

Inter process Communication – Semaphore

Implement the solution for Bounded Buffer (Producer-Consumer) problem using inter process
communication technique – Semaphores.

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

#include <semaphore.h>

#define BUFFER_SIZE 5

sem_t empty, full;

pthread_mutex_t mutex;

int buffer[BUFFER_SIZE];

int in = 0, out = 0;

void *producer(void *arg) {

int item;

while (1) {

item = rand() % 100; // Produce random item

sem_wait(&empty);

pthread_mutex_lock(&mutex);

buffer[in] = item;

printf("Produced: %d\n", item);

in = (in + 1) % BUFFER_SIZE;

pthread_mutex_unlock(&mutex);

sem_post(&full);

sleep(1);

}
void *consumer(void *arg) {

int item;

while (1) {

sem_wait(&full);

pthread_mutex_lock(&mutex);

item = buffer[out];

printf("Consumed: %d\n", item);

out = (out + 1) % BUFFER_SIZE;

pthread_mutex_unlock(&mutex);

sem_post(&empty);

sleep(2);

int main() {

pthread_t producer_thread, consumer_thread;

sem_init(&empty, 0, BUFFER_SIZE);

sem_init(&full, 0, 0);

pthread_mutex_init(&mutex, NULL);

pthread_create(&producer_thread, NULL, producer, NULL);

pthread_create(&consumer_thread, NULL, consumer, NULL);

pthread_join(producer_thread, NULL);

pthread_join(consumer_thread, NULL);

sem_destroy(&empty);

sem_destroy(&full);

pthread_mutex_destroy(&mutex);
return 0;

II. Implement the solution for Readers-Writers problem using inter process communication
technique – Semaphores.

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

#include <semaphore.h>

sem_t mutex, writeblock;

int data = 0, readcount = 0;

void *reader(void *arg) {

int f;

f = *((int *)arg);

sem_wait(&mutex);

readcount++;

if (readcount == 1)

sem_wait(&writeblock);

sem_post(&mutex);

printf("Data read by the reader%d is %d\n", f, data);

sleep(1);
sem_wait(&mutex);

readcount--;

if (readcount == 0)

sem_post(&writeblock);

sem_post(&mutex);

void *writer(void *arg) {

int f;

f = *((int *)arg);

sem_wait(&writeblock);

data++;

printf("Data written by the writer%d is %d\n", f, data);

sleep(1);

sem_post(&writeblock);

int main() {

pthread_t rtid[5], wtid[5];

int i;

sem_init(&mutex, 0, 1);

sem_init(&writeblock, 0, 1);

for (i = 0; i <= 2; i++) {

pthread_create(&wtid[i], NULL, writer, (void *)&i);

pthread_create(&rtid[i], NULL, reader, (void *)&i);

for (i = 0; i <= 2; i++) {

pthread_join(wtid[i], NULL);

pthread_join(rtid[i], NULL);

return 0;
}

III. Implement the solution for Dining-Philosopher problem using inter process communication
technique – Semaphores.

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

#include <semaphore.h>

#include <unistd.h>

#define N 5

#define THINKING 2

#define HUNGRY 1

#define EATING 0

#define LEFT (phnum + 4) % N

#define RIGHT (phnum + 1) % N

int state[N];

int phil[N] = {0, 1, 2, 3, 4};

sem_t mutex;

sem_t S[N];

void test(int phnum) {

if (state[phnum] == HUNGRY && state[LEFT] != EATING && state[RIGHT] != EATING) {

state[phnum] = EATING;

sleep(2);

printf("Philosopher %d takes fork %d and %d\n", phnum + 1, LEFT + 1, phnum + 1);


printf("Philosopher %d is Eating\n", phnum + 1);

sem_post(&S[phnum]);

void take_fork(int phnum) {

sem_wait(&mutex);

state[phnum] = HUNGRY;

printf("Philosopher %d is Hungry\n", phnum + 1);

test(phnum);

sem_post(&mutex);

sem_wait(&S[phnum]);

sleep(1);

void put_fork(int phnum) {

sem_wait(&mutex);

state[phnum] = THINKING;

printf("Philosopher %d putting fork %d and %d down\n", phnum + 1, LEFT + 1, phnum + 1);

printf("Philosopher %d is thinking\n", phnum + 1);

test(LEFT);

test(RIGHT);

sem_post(&mutex);

void *philosopher(void *num) {

while (1) {

int *i = num;

sleep(1);

take_fork(*i);

sleep(0);
put_fork(*i);

int main() {

int i;

pthread_t thread_id[N];

sem_init(&mutex, 0, 1);

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

sem_init(&S[i], 0, 0);

for (i = 0; i < N; i++) {

pthread_create(&thread_id[i], NULL, philosopher, &phil[i]);

printf("Philosopher %d is thinking\n", i + 1);

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

pthread_join(thread_id[i], NULL);

}
LAB – 11

FORK and JOIN construct

I. Write a program where parent process take average of the odd numbers and child
process will take the average of even numbers present in a given Aadhar number of a
person. Use FORK and JOIN construct.
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

void calculate_average(int numbers[], int size, int is_odd) {


int sum = 0, count = 0;
for (int i = 0; i < size; i++) {
if ((numbers[i] % 2 == 0 && !is_odd) || (numbers[i] % 2 != 0 && is_odd)) {
sum += numbers[i];
count++;
}
}
if (count > 0) {
float average = (float)sum / count;
printf("Average of %s numbers: %.2f\n", (is_odd ? "odd" : "even"), average);
} else {
printf("No %s numbers found.\n", (is_odd ? "odd" : "even"));
}
}

int main() {
int numbers[] = {12, 23, 34, 45, 56, 67, 78, 89, 90, 101};
int size = sizeof(numbers) / sizeof(numbers[0]);

pid_t pid = fork();

if (pid == 0) { // Child process


calculate_average(numbers, size, 0); // Calculate average of even numbers
} else if (pid > 0) { // Parent process
wait(NULL); // Wait for child process to finish
calculate_average(numbers, size, 1); // Calculate average of odd numbers
} else { // Fork failed
fprintf(stderr, "Fork failed\n");
return 1;
}

return 0;
}
II. II. Write a program where parent process finds additive primes and child process finds
circular prime for a given prime list array. Use FORK and JOIN construct.
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/wait.h>

bool is_prime(int num) {


if (num <= 1)
return false;
for (int i = 2; i * i <= num; i++) {
if (num % i == 0)
return false;
}
return true;
}

bool is_circular_prime(int num) {


int temp = num, digit_count = 0;
while (temp > 0) {
digit_count++;
temp /= 10;
}
temp = num;
for (int i = 0; i < digit_count; i++) {
if (!is_prime(temp))
return false;
int last_digit = temp % 10;
temp = last_digit * (int)(pow(10, digit_count - 1)) + temp / 10;
}
return true;
}

void find_primes(int prime_list[], int size, int is_additive_prime) {


for (int i = 0; i < size; i++) {
if ((is_prime(prime_list[i]) && is_additive_prime) || (is_circular_prime(prime_list[i])
&& !is_additive_prime))
printf("%d is %s prime.\n", prime_list[i], (is_additive_prime ? "additive" :
"circular"));
}
}

int main() {
int prime_list[] = {7, 11, 13, 17, 23, 29, 31, 37, 41, 47};
int size = sizeof(prime_list) / sizeof(prime_list[0]);

pid_t pid = fork();


if (pid == 0) { // Child process
find_primes(prime_list, size, 0); // Find circular primes
} else if (pid > 0) { // Parent process
wait(NULL); // Wait for child process to finish
find_primes(prime_list, size, 1); // Find additive primes
} else { // Fork failed
fprintf(stderr, "Fork failed\n");
return 1;
}

return 0;
}

You might also like