0% found this document useful (0 votes)
6 views35 pages

Key Terms in Systems Programming

The document provides definitions and explanations of key terms in systems programming, including system calls, named pipes, sockets, shell scripts, and semaphores. It differentiates between conventional function calls and system calls, discusses dynamic memory allocation, and outlines memory management strategies such as static, stack, and heap allocation. Additionally, it includes examples of C programs, shell scripting, file permissions, and compilation steps in Linux.

Uploaded by

Shem Gikunda
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)
6 views35 pages

Key Terms in Systems Programming

The document provides definitions and explanations of key terms in systems programming, including system calls, named pipes, sockets, shell scripts, and semaphores. It differentiates between conventional function calls and system calls, discusses dynamic memory allocation, and outlines memory management strategies such as static, stack, and heap allocation. Additionally, it includes examples of C programs, shell scripting, file permissions, and compilation steps in Linux.

Uploaded by

Shem Gikunda
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

Define the following terms as used in systems programming : System

call , Named pipe , Socket , Shell script , Semaphore

Here are clear definitions of the terms as used in systems programming:

1.​ System call​


A system call is a request made by a program to the operating system’s kernel to
perform a service such as process control, file manipulation, device handling, or
communication.​

○​ Example: read(), write(), fork(), and exec() in UNIX/Linux.​

2.​ Named pipe (FIFO)​


A named pipe is an inter-process communication (IPC) mechanism that allows
unrelated processes to communicate with each other by reading and writing through
a special file in the filesystem. Unlike anonymous pipes, named pipes persist as
objects in the filesystem and can be accessed by multiple processes.​

○​ Example: Creating one with mkfifo mypipe in Linux.​

3.​ Socket​
A socket is an endpoint for bidirectional communication between processes, often
over a network (TCP/UDP) or locally (UNIX domain sockets). It provides a standard
interface for processes to send and receive data.​

○​ Example: Web servers use sockets to communicate with clients via HTTP.​

4.​ Shell script​


A shell script is a text file containing a sequence of commands for a UNIX/Linux shell
(such as bash, sh, or zsh) to execute. It is used for automating tasks like file
manipulation, program execution, and system administration.​

Example:​

#!/bin/bash
echo "Hello, World!"

○​
5.​ Semaphore​
A semaphore is a synchronization primitive used to control access to shared
resources in concurrent systems. It is essentially a counter that manages how many
processes can access a resource simultaneously, preventing race conditions.​

○​ Types:​
■​ Binary semaphore (acts like a lock: 0 or 1).​

■​ Counting semaphore (allows multiple concurrent accesses).​

Differentiate between conventional function call and system call

1. Definition

●​ Conventional function call:​


A normal call to a function written in the same program or a library, executed entirely
in user mode without involving the operating system kernel.​

●​ System call:​
A request from a program to the operating system kernel to perform a privileged
operation (e.g., I/O, process control).​

2. Mode of Execution

●​ Function call: Runs only in user mode.​

●​ System call: Causes a mode switch from user mode to kernel mode, because only
the kernel can perform certain critical tasks.​

3. Overhead (Cost)

●​ Function call: Very fast, since it’s just transferring control to another function within
the same memory space.​

●​ System call: Slower, because switching to kernel mode and back requires extra
CPU instructions and context saving.​

4. Purpose

●​ Function call: Used for logical grouping of code, reusability, modularity.​

●​ System call: Used to access system resources such as files, devices, memory, or
processes that user code cannot directly manipulate.​

5. Examples
Function call:​

int add(int a, int b) { return a + b; }
int sum = add(3, 5); // normal function call

●​

System call:​

int fd = open("[Link]", O_RDONLY); // system call to open a file
Explain how dynamic memory allocation scheme enhance memory
utilization

🔹 1. What is dynamic memory allocation?


Dynamic memory allocation is the process of assigning memory to a program at runtime
(instead of compile-time). Functions like malloc(), calloc(), realloc() in C, or new in
C++ allow a program to request memory from the heap when needed and release it when no
longer in use (free() or delete).

🔹 2. How it enhances memory utilization


1.​ Efficient use of memory (no wastage at compile time)​

○​ In static allocation, the memory size must be known in advance, which can
lead to over-allocation (wasting space) or under-allocation (program
crash).​

○​ With dynamic allocation, memory is requested only when needed and in the
exact required size, reducing wastage.​

2.​ Flexibility for variable-sized data​

○​ Programs dealing with unpredictable data sizes (e.g., text editors,


databases, linked lists) benefit from dynamic memory since they can grow or
shrink structures as needed.​

○​ Example: A linked list can expand by allocating memory for new nodes on
demand, unlike static arrays which have fixed size.​

3.​ Better sharing of memory among processes​

○​ Dynamic allocation allows multiple processes or threads to request and


release memory as they run, ensuring that unused memory is returned to the
system and can be reallocated elsewhere.​
4.​ Support for complex data structures​

○​ Structures like linked lists, trees, hash tables, and graphs rely on dynamic
allocation to create nodes only when required. This prevents large chunks of
unused memory from being reserved statically.​

5.​ Memory reuse (deallocation)​

○​ Once a block of dynamically allocated memory is freed, it can be reused by


another part of the program or even another program, enhancing overall
system memory utilization.​

🔹 3. Example (C Code)
#include <stdio.h>
#include <stdlib.h>

int main() {
int n;
printf("Enter number of elements: ");
scanf("%d", &n);

// Allocate memory dynamically


int *arr = (int *) malloc(n * sizeof(int));

// Use the memory


for(int i=0; i<n; i++) arr[i] = i+1;

// Print values
for(int i=0; i<n; i++) printf("%d ", arr[i]);

free(arr); // Free the memory for reuse


return 0;
}

👉 Here memory is allocated only as much as the user requires, unlike a statically
declared array of fixed size.

Explain the syntax of how to print or access value of UDV ( User defined
variables ) and define variable vech as "BUS" and n as "10"

🔹 1. User Defined Variables (UDVs) in Shell


In Unix/Linux shell scripting, user defined variables (UDVs) are created by assigning
values to names.

Syntax
variable_name=value # define
echo $variable_name # access/print

●​ No spaces allowed around = when assigning.​

●​ To access the value, prefix the variable name with a $.​

●​ By default, all variables are treated as strings, unless used in arithmetic.​

🔹 2. Example with your variables


Define vech as "BUS" and n as "10":

vech="BUS"
n="10"

# Printing values
echo $vech
echo $n

🔹 3. Output
BUS
10

✅ Summary:
●​ Definition (Assignment) → varname=value​

●​ Access/Print → echo $varname​

Explain the following in relation to memory management : Static


allocation , Stack allocation , Heap allocation
🔹 1. Static Allocation
●​ Definition: Memory is allocated at compile time for variables whose size and
lifetime are known in advance.​

●​ The allocated memory remains fixed throughout program execution and is


released only when the program ends.​

●​ Stored in the Data Segment of memory.​

Examples:

int x = 10; // global variable (static allocation)


static int y = 20; // static variable

Pros:

●​ Fast (no runtime overhead).​

●​ Simple to manage (compiler handles it).​

Cons:

●​ Inflexible (size must be known at compile time).​

●​ Can waste memory if over-allocated.​

🔹 2. Stack Allocation
●​ Definition: Memory is allocated from the stack for local variables inside functions.​

●​ Automatic allocation/deallocation happens when functions are called and return.​

●​ Managed using a Last-In, First-Out (LIFO) discipline.​

Examples:

void func() {
int a = 5; // stack allocation
char str[20]; // stack allocation
}
Pros:

●​ Very fast (just moves stack pointer).​

●​ Automatically managed (no need for manual free).​

Cons:

●​ Limited in size (stack memory is small).​

●​ Data cannot persist after the function ends.​

🔹 3. Heap Allocation
●​ Definition: Memory is allocated from the heap at runtime using functions like
malloc(), calloc(), or new.​

●​ The programmer must explicitly free the memory using free() or delete.​

Examples:

int *p = (int*) malloc(sizeof(int)); // heap allocation


*p = 50;
free(p); // must be freed

Pros:

●​ Flexible (size determined at runtime).​

●​ Suitable for dynamic data structures (linked lists, trees, graphs).​

Cons:

●​ Slower than stack/static allocation.​

●​ Risk of memory leaks (if not freed).​

●​ Can suffer from fragmentation.​

✅ Comparison Table
Feature Static Stack Allocation Heap Allocation
Allocation

When Compile time Function call Runtime (on


allocated request)

Lifetime Entire program Until function ends Until freed manually

Speed Fast Very fast Slowest

Flexibility None (fixed size) Limited (depends on stack High (variable size)
size)

Location Data segment Stack segment Heap segment

👉 In short:
●​ Static = fixed for entire program.​

●​ Stack = automatic per function call.​

●​ Heap = dynamic, programmer-controlled.​

Write a console application that gets its input from the keyboard or a
disk , and write its output to then display screen via the C++ iostream

🔹
member functions get () and put ()
Code Example
#include <iostream>
#include <fstream>
using namespace std;

int main() {
char ch;
int choice;

cout << "Choose input source:\n";


cout << "1. Keyboard\n";
cout << "2. File (disk)\n";
cout << "Enter choice: ";
cin >> choice;

// Clear newline left in input buffer


[Link]();
if (choice == 1) {
cout << "\nEnter text (press ENTER then CTRL+D or CTRL+Z to
stop):\n";
while ([Link](ch)) { // get() reads one character
[Link](ch); // put() outputs one character
}
}
else if (choice == 2) {
string filename;
cout << "\nEnter filename: ";
getline(cin, filename);

ifstream infile(filename); // open file for reading


if (!infile) {
cerr << "Error: Could not open file " << filename <<
endl;
return 1;
}

while ([Link](ch)) { // read char by char


[Link](ch); // write char to console
}

[Link]();
}
else {
cout << "Invalid choice!" << endl;
}

return 0;
}

🔹 How it works
1.​ The user selects input source (keyboard or file).​

2.​ If keyboard, program reads characters until CTRL+D (Linux/Mac) or CTRL+Z


(Windows).​

3.​ If file, program asks for a filename and displays its content.​
4.​ [Link](ch) and [Link](ch) → read a single character.​

5.​ [Link](ch) → prints that character to the screen.​

✅ Example run (keyboard input):


Choose input source:
1. Keyboard
2. File (disk)
Enter choice: 1

Enter text (press ENTER then CTRL+D to stop):


Hello World!
Hello World!

✅ Example run (file input):


Choose input source:
1. Keyboard
2. File (disk)
Enter choice: 2

Enter filename: [Link]


(This will print contents of [Link] to screen)

Explain how you can make changes to permissions of a file . The file
gives user full access , group read and execute permissions , and other ,
execute permissions

🔹 1. Understanding File Permissions


File permissions are divided into three categories:

●​ User (u) → the file owner​

●​ Group (g) → users in the file’s group​

●​ Others (o) → all other users​

Each category can have:


●​ r = read​

●​ w = write​

●​ x = execute​

🔹 2. Requirement (as per your question)


●​ User (owner) → full access (read, write, execute) → rwx​

●​ Group → read and execute only → r-x​

●​ Others → execute only → --x​

So the permission string becomes:

rwx r-x --x

🔹 3. Symbolic Method (using chmod)


You can set this with:

chmod u=rwx,g=rx,o=x filename

Explanation:

●​ u=rwx → user gets full rights​

●​ g=rx → group gets read + execute​

●​ o=x → others get execute only​

🔹 4. Numeric (Octal) Method


Permissions can also be set with octal numbers:

●​ rwx = 7 (4+2+1)​
●​ r-x = 5 (4+0+1)​

●​ --x = 1 (0+0+1)​

So the combined value is: 751

Command:

chmod 751 filename

🔹 5. Verify Permissions
After changing, you can check with:

ls -l filename

Expected output:

-rwxr-x--x 1 user group size date filename

✅ Summary:​
You can change permissions using:

●​ Symbolic mode: chmod u=rwx,g=rx,o=x filename​

●​ Octal mode: chmod 751 filename​

📄
Write a c program of factorial of a number and display the result
Code: Factorial in C
#include <stdio.h>

int main() {
int n, i;
unsigned long long fact = 1; // use long long for large
factorials

printf("Enter a number: ");


scanf("%d", &n);

if (n < 0) {
printf("Error! Factorial of a negative number doesn’t
exist.\n");
} else {
for (i = 1; i <= n; i++) {
fact *= i;
}
printf("Factorial of %d = %llu\n", n, fact);
}

return 0;
}

🔹 Example Run
Enter a number: 5
Factorial of 5 = 120

✅ This is the iterative version (using a loop).


Explain the steps of how you would compile and run the above program
on Linux

🔹 Steps to Compile and Run in Linux


1. Write the program
Open a text editor (e.g., nano, vim, or gedit):​

nano factorial.c

●​
●​ Paste the program code inside and save (CTRL+O, ENTER, then CTRL+X in nano).​

2. Compile the program


Use the GNU C Compiler (gcc) to compile:​

gcc factorial.c -o factorial

●​ Explanation:​

○​ gcc → compiler​
○​ factorial.c → source code file​

○​ -o factorial → name of the output executable (otherwise it defaults to


[Link])​

3. Run the program


Execute the compiled program:​

./factorial

●​

4. Provide input

Example interaction:

Enter a number: 5
Factorial of 5 = 120

5. (Optional) Debugging common issues


If you forget -o factorial, the program will compile to [Link]. Run it with:​

./[Link]

●​

If you get permission denied, make sure it’s executable:​



chmod +x factorial
./factorial

Use shell script Unix commands to define and initialize separately the
array "shapes " that stores a shape "square"

🔹 Step 1: Define the array (empty at first)


shapes=()

🔹 Step 2: Initialize with one element ("square")


shapes[0]="square"
🔹 Step 3: Access / Print the element
echo ${shapes[0]}

🔹 Full Example Script


#!/bin/bash

# Define array
shapes=()

# Initialize with "square"


shapes[0]="square"

# Display the value


echo "The shape is: ${shapes[0]}"

🔹 Output
The shape is: square

Discuss a simple implementation of malloc and free ()

🔹 1. What malloc() and free() do


●​ malloc(size) → allocates a block of memory of given size from the heap and
returns a pointer to it.​

●​ free(ptr) → releases the previously allocated block so it can be reused later.​

Behind the scenes, the OS provides a big chunk of memory to the program’s heap. Then
malloc and free manage that heap.

🔹 2. Idea of a Simple Implementation


We can imagine:

●​ The heap is just a large array of bytes.​

●​ We keep a small header before each allocated block that stores its size and whether
it’s free or in use.​
●​ malloc() searches for a free block big enough.​

●​ free() marks the block as available again.​

🔹 3. Minimal Example (Educational Only)


#include <stdio.h>
#include <unistd.h> // for sbrk()

typedef struct Block {


size_t size; // size of the block
int free; // free = 1 if available, 0 if in use
struct Block *next; // linked list of blocks
} Block;

#define BLOCK_SIZE sizeof(Block)

Block *freeList = NULL;

// Simple malloc
void *my_malloc(size_t size) {
Block *curr, *prev;
void *result;

if (!freeList) { // first call


curr = sbrk(0);
void *request = sbrk(size + BLOCK_SIZE);
if (request == (void*) -1) return NULL;

curr->size = size;
curr->free = 0;
curr->next = NULL;
freeList = curr;
result = (void*)(curr+1);
return result;
}

curr = freeList;
while (curr) {
if (curr->free && curr->size >= size) {
curr->free = 0;
result = (void*)(curr+1);
return result;
}
if (!curr->next) break;
curr = curr->next;
}

// request more memory


void *request = sbrk(size + BLOCK_SIZE);
if (request == (void*) -1) return NULL;

Block *newBlock = request;


newBlock->size = size;
newBlock->free = 0;
newBlock->next = NULL;
curr->next = newBlock;
result = (void*)(newBlock+1);
return result;
}

// Simple free
void my_free(void *ptr) {
if (!ptr) return;
Block *block = (Block*)ptr - 1; // move back to header
block->free = 1;
}

// Test program
int main() {
int *arr = (int*) my_malloc(5 * sizeof(int));
for (int i = 0; i < 5; i++) arr[i] = i * 10;

for (int i = 0; i < 5; i++) printf("%d ", arr[i]);


printf("\n");

my_free(arr);
return 0;
}

🔹 4. How this works


●​ We maintain a linked list of blocks (each has size, free flag, next pointer).​

●​ malloc:​

○​ Searches free blocks.​

○​ If none is available, uses sbrk() to ask the OS for more heap memory.​

●​ free:​

○​ Marks the block as free so it can be reused.​

🔹 5. Limitations (compared to real malloc)


●​ No splitting large free blocks.​

●​ No coalescing adjacent free blocks.​

●​ No thread-safety.​

●​ Uses sbrk() (old system call) instead of mmap() or more advanced allocators.​

Explain the difficulties that arise in the way the operating system
handles interrupts and the scheduling policies of the operating system

🔹 1. Difficulties in Handling Interrupts


An interrupt is a signal that temporarily halts the CPU’s normal execution so the OS can
respond to an event (e.g., I/O completion, hardware request, system call).

Main difficulties:

1.​ Interrupt priority management​

○​ Multiple devices can raise interrupts simultaneously.​

○​ The OS must decide which interrupt to handle first (e.g., disk I/O vs
keyboard input).​

○​ Poor prioritization can cause delays or even missed interrupts.​


2.​ Context switching overhead​

○​ The CPU must save the current process state before servicing the
interrupt.​

○​ Frequent interrupts lead to high overhead (performance degradation).​

3.​ Interrupt latency​

○​ The delay between when an interrupt occurs and when it’s serviced.​

○​ If too high, real-time processes (like multimedia or embedded systems) may


fail.​

4.​ Nested interrupts​

○​ Handling an interrupt while already servicing another one is tricky.​

○​ Requires mechanisms (like interrupt masking) to prevent conflicts.​

5.​ Concurrency and synchronization​

○​ Interrupt handlers may share data with running processes.​

○​ Risk of race conditions if access is not properly synchronized.​

🔹 2. Difficulties in Scheduling Policies


The scheduler decides which process runs on the CPU at any given time. The goal is to
balance performance, fairness, and responsiveness.

Main difficulties:

1.​ Conflicting objectives​

○​ Throughput (maximize work done),​

○​ Turnaround time (minimize job completion time),​

○​ Response time (quick replies for interactive users),​

○​ Fairness (equal treatment of processes).​


These objectives often conflict, so no single scheduling policy satisfies all.​
2.​ Starvation​

○​ In policies like priority scheduling, low-priority processes may never execute


if high-priority ones keep arriving.​

3.​ Overhead of context switching​

○​ Preemptive scheduling (e.g., Round Robin) requires frequent context


switches, which waste CPU time.​

4.​ Predicting process behavior​

○​ Some policies (e.g., Shortest Job Next) require knowing process execution
time in advance, which is usually impossible.​

5.​ Fairness in multiprogramming​

○​ In multi-user or multi-task systems, ensuring fair CPU time across processes


is complex.​

6.​ Real-time constraints​

○​ For real-time systems, the scheduler must meet strict deadlines. Missing
deadlines can cause system failure.​

Explain the following three main Scheduling used in operating systems :


Long-term scheduler , Medium-term scheduler and Short-term scheduler

🔹 1. Long-Term Scheduler (Job


Scheduler)
●​ Definition: Decides which jobs/processes are admitted into the system for
processing.​

●​ It controls the degree of multiprogramming (how many processes are in memory at


once).​

●​ Runs infrequently (seconds/minutes).​

Responsibilities:

●​ Selects jobs from the job queue (on disk) and loads them into main memory.​
●​ Balances I/O-bound and CPU-bound jobs for efficient resource utilization.​

Example: In a batch system, the long-term scheduler decides which jobs from the batch go
into memory for execution.

🔹 2. Medium-Term Scheduler
●​ Definition: Temporarily removes (suspends) some processes from memory and later
reintroduces them.​

●​ Helps balance CPU and I/O load and improves overall performance.​

●​ Runs occasionally (more frequent than long-term, less frequent than short-term).​

Responsibilities:

●​ Implements swapping (moving processes in/out of memory).​

●​ Reduces degree of multiprogramming if system is overloaded.​

●​ Can suspend low-priority or waiting processes.​

Example: If too many processes are waiting for I/O, the medium-term scheduler may
suspend some to free up CPU cycles for others.

🔹 3. Short-Term Scheduler (CPU


Scheduler)
●​ Definition: Decides which process from the ready queue gets the CPU next.​

●​ Runs very frequently (milliseconds).​

Responsibilities:

●​ Allocates CPU to one of the ready processes.​

●​ Implements scheduling algorithms like Round Robin, Priority Scheduling, FCFS, or


SJF.​
●​ Directly affects system response time and throughput.​

Example: In a time-sharing system, the short-term scheduler picks the next process for CPU
execution after a time slice expires.

✅ Comparison Table
Feature Long-Term Scheduler Medium-Term Short-Term Scheduler
Scheduler

Also called Job Scheduler Swapper CPU Scheduler

Main Admit jobs to system Suspend/resume Select job for CPU


function jobs

Frequency Infrequent Occasional Very frequent (ms)


(seconds/minutes)

Focus Degree of Balance system load CPU utilization,


multiprogramming response time

Example Batch system job Suspend I/O-heavy Choose next process in


admission jobs ready queue

👉 In short:
●​ Long-term = controls which jobs enter the system.​

●​ Medium-term = suspends/resumes jobs to balance performance.​

●​ Short-term = chooses which job runs next on the CPU.​

What is a device controller

🔹 Device Controller
A device controller is a hardware component (usually a chip or circuit board) that acts as
an interface between the CPU (or operating system) and a peripheral device such as a
disk, printer, keyboard, or network card.

It translates high-level commands from the OS into the low-level, device-specific


signals needed to control the physical device.
🔹 Functions of a Device Controller
1.​ Communication with the device​

○​ Sends commands to the device (e.g., "read sector", "print character").​

○​ Receives status/error signals from the device.​

2.​ Data transfer​

○​ Moves data between the device and main memory (possibly via Direct
Memory Access – DMA).​

3.​ Buffering​

○​ Temporarily stores data in a buffer to match speed differences between the


CPU and the device.​

4.​ Interrupt handling​

○​ Sends an interrupt to the CPU when a device operation (e.g., I/O


completion) finishes.​

🔹 Types of Device Controllers


●​ Single-device controller → controls one device (e.g., a keyboard controller).​

●​ Multi-device controller → controls multiple devices of the same type (e.g., a disk
controller for several hard drives).​

🔹 Example
●​ Disk controller: Translates OS read/write requests into specific cylinder, track, and
sector operations on the hard disk.​

●​ Graphics controller (GPU): Manages display output.​

●​ USB controller: Interfaces between CPU and USB devices.​

✅ In short:​
A device controller is the middleman between the OS and hardware devices, handling
the details of device operation so the OS and applications don’t have to deal with low-level
hardware logic.
What is device independence

🔹 Device Independence
Device independence means that application programs can perform input/output (I/O)
operations without needing to know the specific details of the hardware device being
used.

In other words, the same program can read/write data regardless of whether the I/O device
is a disk, printer, terminal, or network card, as long as there is an appropriate driver and
OS support.

🔹 Why Device Independence is Important


●​ Makes programs portable (they work on different systems/devices without
modification).​

●​ Reduces programmer effort, since no need to handle device-specific operations.​

●​ Promotes flexibility – devices can be replaced or upgraded without changing


application code.​

🔹 How It Is Achieved
●​ Through the Operating System’s I/O subsystem (providing a uniform interface for
I/O).​

●​ Using device drivers that translate generic OS I/O requests into device-specific
commands.​

●​ Example:​

○​ A program issues a generic read(file) call.​

○​ OS decides whether that file is on a hard disk, SSD, or USB stick.​

○​ The correct device driver handles the low-level communication.​

🔹 Example in Practice
●​ When you write to a file using printf() in C or cout in C++, you don’t need to
know if the data is stored on a hard disk, SSD, USB drive, or network file system.​
●​ Similarly, a document can be printed without the program knowing whether the printer
is HP, Canon, or Epson.​

✅ In short:​
Device independence means programs are written in a way that they don’t depend on the
type of physical I/O device, but rely on the OS to handle the device-specific details.

Explain the following techniques of paging : Demand paging ,


Anticipatory paging

🔹 1. Demand Paging
●​ Definition: A paging technique where a page is brought into main memory (RAM)
only when it is needed (i.e., when a page fault occurs).​

●​ Pages are not loaded in advance; they are loaded on demand.​

How it works:

1.​ Process starts execution with only part of its pages in memory.​

2.​ If the CPU references a page that is not in memory, a page fault occurs.​

3.​ The OS loads the required page from secondary storage (disk) into RAM.​

4.​ Execution resumes.​

Advantages:

●​ Saves memory (only required pages are loaded).​

●​ Faster program startup.​

●​ Efficient for processes that do not use all their pages.​

Disadvantages:

●​ Page faults cause delays (disk access is slow).​

●​ Too many page faults may lead to thrashing (system spends more time swapping
than executing).​
Example: Running a word processor – only the parts of the code and data you use (menus,
editing tools) are loaded, not the entire program.

🔹 2. Anticipatory Paging (Pre-paging)


●​ Definition: A paging technique where the OS preloads pages into memory before
they are actually referenced by the process.​

●​ The idea is to anticipate future page requests based on past behavior or program
logic.​

How it works:

1.​ When a page is brought into memory, the OS may also load the neighboring or
related pages.​

2.​ This reduces the number of page faults if the predictions are correct.​

Advantages:

●​ Fewer page faults → better performance.​

●​ Good for programs with sequential access patterns (e.g., reading a large file or
streaming video).​

Disadvantages:

●​ If predictions are wrong, it wastes memory and I/O bandwidth.​

●​ More overhead if unused pages are loaded.​

Example: When reading a book in an e-reader, if you open page 50, the system may also
pre-load pages 51 and 52 in anticipation that you will read them next.

🔹 Quick Comparison Table


Feature Demand Paging Anticipatory Paging (Pre-paging)

When pages are Only when needed (on Before they are needed (predicted)
loaded demand)

Page faults Higher (initially) Lower (if prediction is correct)


Memory use Efficient (loads only used May waste memory if wrong pages
pages) loaded

Best for Random access programs Sequential/ predictable access

✅ In short:
●​ Demand paging = “load when asked.”​

●​ Anticipatory paging = “load before being asked.”​

Discuss any three file access permissions . Explain how the permissions
associated with a file impact on the system's operations

🔹 Three File Access Permissions in Unix/Linux


In most operating systems (especially Unix/Linux), every file has three main access
permissions:

1. Read (r)

●​ Allows a user to open and view the contents of a file.​

●​ For directories: allows listing of directory contents (ls).​

Example: If a user has read permission on a text file, they can use cat, less, or more to
view it.

2. Write (w)

●​ Allows a user to modify or delete the contents of a file.​

●​ For directories: allows adding, deleting, or renaming files within the directory.​

Example: With write permission, a user can use nano or vim to edit a file, or even delete it.

3. Execute (x)

●​ Allows a file to be run as a program/script.​

●​ For directories: allows a user to enter the directory and access files inside (using
cd).​
Example: A shell script must have execute permission for a user to run it directly
(./[Link]).

🔹 How Permissions Impact System Operations


1.​ Security & Privacy​

○​ Permissions control who can access files and in what way.​

○​ For example, a confidential payroll file may give only the administrator
read/write access, while denying others all permissions.​

2.​ System Stability​

○​ Prevents unauthorized users from modifying critical system files.​

○​ For instance, /etc/passwd should only be writable by the system


administrator; otherwise, system integrity is at risk.​

3.​ Collaboration & Resource Sharing​

○​ Permissions make it possible for multiple users to safely share resources.​

○​ Example: In a project directory, developers may have read/write access,


testers only read, and the public no access at all.​

✅ In short:
●​ Read (r) → view contents.​

●​ Write (w) → modify/delete contents.​

●​ Execute (x) → run file / enter directory.​

●​ These permissions protect system files, ensure security, and enable controlled
collaboration.​

Explain how the Operating System effectively manages various


processes by using the following : Interrupt Handlers , Schedulers ,
Inter-Process Communicators

🔹 1. Interrupt Handlers
●​ Definition: Special routines in the OS that respond to interrupts (signals from
hardware or software that something needs attention).​

●​ Role in Process Management:​

○​ When an I/O device, timer, or another event generates an interrupt, the CPU
stops its current execution and jumps to the interrupt handler.​

○​ The handler determines what caused the interrupt (e.g., I/O completion,
system call, error).​

○​ It updates the process state (e.g., moves process from waiting → ready), then
resumes execution.​

Example:

●​ A process requests disk I/O → goes to waiting state.​

●​ When disk finishes reading, it sends an interrupt → handler updates process status
to ready → scheduler can now assign CPU to it.​

👉 Impact: Ensures efficient coordination between CPU and I/O, avoiding wasted CPU
cycles.

🔹 2. Schedulers
Schedulers decide which process runs when, since CPU and resources are limited.

●​ Long-term scheduler: Controls how many jobs enter the system (degree of
multiprogramming).​

●​ Medium-term scheduler: Temporarily suspends/resumes processes to balance load


(e.g., swapping).​

●​ Short-term scheduler (CPU scheduler): Picks which process from the ready queue
gets CPU next.​

Role in Process Management:

●​ Prevents starvation by applying fair policies (e.g., Round Robin, Priority Scheduling).​

●​ Improves system throughput, response time, and CPU utilization.​

Example:
●​ If three processes are in the ready queue, the short-term scheduler picks the next
process for CPU based on its policy.​

👉 Impact: Keeps the system responsive, fair, and efficient.


🔹 3. Inter-Process Communicators (IPC)
●​ Definition: Mechanisms that allow processes to exchange data and coordinate
actions.​

●​ Role in Process Management:​

○​ Processes often need to cooperate (e.g., one produces data, another


consumes it).​

○​ IPC provides safe and structured ways for processes to communicate.​

Techniques include:

●​ Pipes (unidirectional data flow).​

●​ Message Queues (send/receive messages).​

●​ Shared Memory (processes read/write to same memory region, usually with


synchronization tools like semaphores).​

●​ Sockets (communication across networks).​

Example:

●​ A web server (producer) sends a client’s request data to a worker process


(consumer) using shared memory or sockets.​

👉 Impact: Enables concurrency, synchronization, and cooperation among processes


without data corruption.

Outline the main purpose of IPC

🔹 Main Purpose of Inter-Process Communication (IPC)


The main purpose of IPC is to enable processes to exchange data and coordinate their
activities so that they can work together efficiently and correctly.
🔹 Key Purposes of IPC
1.​ Data Sharing​

○​ Allows processes to share information (e.g., producer process creates data,


consumer process uses it).​

2.​ Communication​

○​ Provides a mechanism for processes to send and receive messages,


whether on the same machine or across a network.​

3.​ Synchronization​

○​ Ensures processes execute in the right order without interfering with each
other (avoiding race conditions).​

4.​ Resource Sharing​

○​ Helps coordinate access to shared resources like files, memory, or devices.​

5.​ Modularity​

○​ Allows large applications to be divided into smaller cooperating processes


that can run independently but still interact.​

✅ In short:​
The main purpose of IPC is to allow processes to communicate, share data, and
synchronize their actions, ensuring smooth and efficient multitasking.

Write a C program that implements the getpid() function ( a simple


program )
ChatGPT said:

Got it 👍 Here’s a simple C program that demonstrates use of the getpid() function:
#include <stdio.h>
#include <unistd.h> // for getpid()

int main() {
// getpid() returns the process ID of the calling process
pid_t process_id = getpid();

// Print the process ID


printf("The Process ID (PID) of this program is: %d\n",
process_id);

return 0;
}

🔹 Explanation
●​ #include <unistd.h> → required for getpid().​

●​ pid_t → data type used for process IDs.​

●​ getpid() → returns the process ID of the currently running program.​

Output will be something like:​



The Process ID (PID) of this program is: 12345

●​ (The number will vary each time you run the program).​

What will the above program execute


ChatGPT said:

Good follow-up 👍
When you compile and run the getpid() program, here’s what will happen step by step:

🔹 Execution Steps & Output


1.​ The program starts execution as a new process created by the OS.​

2.​ The getpid() function retrieves the process ID (PID) of that running program.​

3.​ The program prints the PID to the screen.​

🔹 Example Output
On running:

$ ./[Link]
The Process ID (PID) of this program is: 4821

●​ The number (4821 here) will be different every time because the OS assigns a new
PID each time the program runs.​

✅ In short:​
The program will print the process ID of itself, showing which unique process number the
OS has assigned to it at that run.

Show how a program that uses the getenv() function retrieves a


particular environment string

🔹 Example C Program Using getenv()


#include <stdio.h>
#include <stdlib.h> // for getenv()

int main() {
// Retrieve the value of the PATH environment variable
char *path = getenv("PATH");

if (path != NULL) {
printf("The PATH environment variable is:\n%s\n", path);
} else {
printf("The PATH environment variable is not set.\n");
}

return 0;
}

🔹 Explanation
●​ #include <stdlib.h> → needed for getenv().​

●​ getenv("NAME") → retrieves the value of the environment variable "NAME".​

●​ Returns a pointer to the string value, or NULL if the variable is not defined.​

🔹 Example Output
$ ./[Link]
The PATH environment variable is:
/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin

(The exact output depends on your system’s PATH variable).

✅ In short:​
The program uses getenv() to fetch and print the value of a specific environment
variable (in this case, "PATH").

Use shell arithmetic to perform the following arithmetic operations : 6 +


3 , 20 mod 3 , 10 * 3

🔹 1. Addition → 6 + 3
echo $((6 + 3))

Output:

🔹 2. Modulus → 20 mod 3
echo $((20 % 3))

Output:

🔹 3. Multiplication → 10 * 3
echo $((10 * 3))

Output:

30

✅ In short:
●​ 6 + 3 = 9​
●​ 20 % 3 = 2​

●​ 10 * 3 = 30​

Use unix command to show how to redirect the output of a command to


another file

🔹 Redirecting Output in Unix/Linux


You can use the redirection operator (>) to send the output of a command to a file.

Example 1: Redirect output of ls to a file


ls > file_list.txt

●​ This saves the output of the ls command into file_list.txt.​

●​ If file_list.txt already exists, it will be overwritten.​

Example 2: Append output instead of overwriting


ls >> file_list.txt

●​ This appends the output of ls to the existing file instead of replacing it.​

Example 3: Redirect output of echo


echo "Hello, Unix World!" > [Link]

●​ Creates a file [Link] containing the text.​

✅ In short:
●​ > → redirect and overwrite.​

●​ >> → redirect and append.​

Common questions

Powered by AI

Stack allocation is very fast and automatically managed, as memory is allocated and deallocated when functions are called and returned, making it suitable for short-lived local variables. However, it is limited in size and cannot persist data after the function ends. In contrast, heap allocation provides flexibility with size determined at runtime, suitable for dynamic data structures, though it is slower and requires manual memory management, posing risks of memory leaks .

Symbolic modes offer an intuitive way to set permissions with user, group, and others explicitly defined, enhancing readability. Numeric modes provide a compact representation, reducing the chance for misconfiguration. However, both methods require careful handling to avoid unauthorized access or modification, particularly for critical system files where security vulnerabilities may arise .

A medium-term scheduler manages system load by swapping processes in and out of the main memory, thus controlling the degree of multiprogramming. It can suspend processes to reduce system overload, balancing the CPU and I/O load, and then resume them later, which helps in optimizing overall performance .

Dynamic memory allocation improves efficiency by allocating memory at runtime based on actual needs, thus minimizing wastage compared to static allocation, which requires pre-determined space that often leads to over-allocation or under-use. Dynamic allocation allows for flexibility in handling variable-sized data and better memory sharing across processes .

Interrupt handlers manage unexpected signal handling, ensuring efficient CPU and I/O device coordination. Schedulers (long-term, medium-term, and short-term) manage process execution order to balance system load and optimize resource utilization. Inter-process communication allows processes to exchange data and coordinate actions, crucial for task cooperation and resource sharing across processes .

Handling interrupts involves prioritizing which signals to address first, managing context-switching overhead, and minimizing interrupt latency. High interrupt latency can adversely affect real-time applications by delaying critical process responses, potentially causing system failures. Nested and concurrent interrupt handling requires mechanisms to avoid conflicts and ensure synchronized data access .

Dynamic memory allocation supports complex data structures by providing memory on demand, essential for structures like linked lists, trees, and hash tables. For instance, linked lists can dynamically allocate nodes as needed, enabling efficient memory use and flexible structure growth compared to static arrays. This dynamic capability allows such structures to adjust their size depending on data requirements .

To compile a C program on Linux, use a text editor to write the code, then compile it with gcc using 'gcc filename.c -o outputname'. Run the executable with './outputname'. Common issues include forgetting to specify the output file, leading to use of './a.out', and permission errors, often solved by 'chmod +x outputname' to make it executable .

A device controller acts as an interface between the CPU and peripheral devices, translating high-level OS commands into specific signals needed for device operation. It manages communication by sending and receiving commands and data, buffering to accommodate speed mismatches, and handling interrupts to notify the CPU about device status changes .

Long-term schedulers decide which jobs enter the system, controlling the degree of multiprogramming. Medium-term schedulers perform swapping to balance system load and free memory space temporarily. Short-term schedulers allocate CPU time to ready queue processes, optimizing system response time and throughput. Together, these schedulers ensure efficient resource utilization and process management .

You might also like