0% found this document useful (0 votes)
2 views23 pages

CEF427 Chapter1

The document discusses Inter Process Communication (IPC) mechanisms, including pipes, FIFO, message queues, shared memory, semaphores, and signals. It explains process creation and termination using the fork() system call, along with details on process IDs, parent-child relationships, and process images. Additionally, it covers process monitoring and the implications of a parent process terminating before its child process.

Uploaded by

akameson17
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)
2 views23 pages

CEF427 Chapter1

The document discusses Inter Process Communication (IPC) mechanisms, including pipes, FIFO, message queues, shared memory, semaphores, and signals. It explains process creation and termination using the fork() system call, along with details on process IDs, parent-child relationships, and process images. Additionally, it covers process monitoring and the implications of a parent process terminating before its child process.

Uploaded by

akameson17
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/ 23

Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

CEF427: ADVANCED OPERATING SYSTEMS

Chapter 1: Introduction to Inter process


communication
I. Introduction

Inter Process Communication (IPC) is a mechanism that involves communication of one process
with another process. This usually occurs only in one system.
Communication can be of two types −

• Between related processes initiating from only one process, such as parent and child
processes.

• Between unrelated processes, or two or more different processes.

Following are some important terms that we need to know before proceeding further on this topic.
Pipes − Communication between two related processes. The mechanism is half duplex meaning the
first process communicates with the second process. To achieve a full duplex i.e., for the second
process to communicate with the first process another pipe is required.
FIFO − Communication between two unrelated processes. FIFO is a full duplex, meaning the first
process can communicate with the second process and vice versa at the same time.
Message Queues − Communication between two or more processes with full duplex capacity. The
processes will communicate with each other by posting a message and retrieving it out of the queue.
Once retrieved, the message is no longer available in the queue.
Shared Memory − Communication between two or more processes is achieved through a shared
piece of memory among all processes. The shared memory needs to be protected from each other by
synchronizing access to all the processes.
Semaphores − Semaphores are meant for synchronizing access to multiple processes. When one
process wants to access the memory (for reading or writing), it needs to be locked (or protected) and
released when the access is removed. This needs to be repeated by all the processes to secure data.
Signals − Signal is a mechanism to communication between multiple processes by way of
signalling. This means a source process will send a signal (recognized by number) and the
destination process will handle it accordingly.

Proposed by Dr. SOP DEFFO Lionel L. 1


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

II. Process information

Before we go into process information, we need to know a few things, such as :


-What is a process? A process is a program in execution.
-What is a program? A program is a file containing the information of a process and how to build
it during run time. When you start execution of the program, it is loaded into RAM and starts
executing.
Each process is identified with a unique positive integer called as process ID or simply PID
(Process Identification number). The kernel usually limits the process ID to 32767, which is
configurable. When the process ID reaches this limit, it is reset again, which is after the system
processes range. The unused process IDs from that counter are then assigned to newly created
processes.
The system call getpid() returns the process ID of the calling process.
#include <sys/types.h>
#include <unistd.h>

pid_t getpid(void);

This call returns the process ID of the calling process which is guaranteed to be unique. This call is
always successful and thus no return value to indicate an error.
Each process has its unique ID called process ID that is fine but who created it? How to get
information about its creator? Creator process is called the parent process. Parent ID or PPID can be
obtained through getppid() call.
The system call getppid() returns the Parent PID of the calling process.
#include <sys/types.h>
#include <unistd.h>

pid_t getppid(void);

This call returns the parent process ID of the calling process. This call is always successful and thus
no return value to indicate an error.
Let us understand this with a simple example.
Following is a program to know the PID and PPID of the calling process.
File name: processinfo.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

Proposed by Dr. SOP DEFFO Lionel L. 2


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

int main() {
int mypid, myppid;
printf("Program to know PID and PPID's information\n");
mypid = getpid();
myppid = getppid();
printf("My process ID is %d\n", mypid);
printf("My parent process ID is %d\n", myppid);
printf("Cross verification of pid's by executing process commands on shell\n");
system("ps -ef");
return 0;
}

On

compilation and execution of the above program, following will be the output.

Proposed by Dr. SOP DEFFO Lionel L. 3


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

Note − The “C” library function system() executes a shell command. The arguments passed to
system() are commands executed on shell. In the above program, command is “ps”, which gives
process status.
The complete information about all running processes and other system related information are
accessible from proc file system available at /proc location.

III. Process Image

Now that we have seen how to get the basic information of process and its parent process, it is time
to look into the details of process/program information.
What exactly is process image? Process image is an executable file required while executing the
program. This image usually contains the following sections −

• Code segment or text segment


• Data segment
• Stack segment
• Heap segment
Following is the pictorial representation of the process image.

Proposed by Dr. SOP DEFFO Lionel L. 4


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

Code segment is a portion of object file or program’s virtual address space that consists of
executable instructions. This is usually read-only data segment and has a fixed size.
Data segment is of two types.

• Initialized
• Un-initialized
Initialized data segment is a portion of the object file or program’s virtual address space that
consists of initialized static and global variables.
Un-initialized data segment is a portion of the object file or program’s virtual address space that
consists of uninitialized static and global variables. Un-initialized data segment is also called BSS
(Block Started by Symbol) segment.
Data segment is read-write, since the values of variables could be changed during run time. This
segment also has a fixed size.
Stack segment is an area of memory allotted for automatic variables and function parameters. It
also stores a return address while executing function calls. Stack uses LIFO (Last-In-First-Out)
mechanism for storing local or automatic variables, function parameters and storing next address or
return address. The return address refers to the address to return after completion of function
execution. This segment size is variable as per local variables, function parameters, and function
calls. This segment grows from a higher address to a lower address.
Heap segment is area of memory allotted for dynamic memory storage such as for malloc() and
calloc() calls. This segment size is also variable as per user allocation. This segment grows from a
lower address to a higher address.
Let us now check how the segments (data and bss segments) size vary with a few sample programs.
Segment size is known by executing the command “size”.

Initial program

File: segment_size1.c
#include<stdio.h>

int main() {
printf("Hello World\n");
return 0;
}

In the following program, an uninitialized static variable is added. This means uninitialized segment
(BSS) size would increase by 4 Bytes. Note − In Linux operating system, the size of int is 4 bytes.
Size of the integer data type depends on the compiler and operating system support.

Proposed by Dr. SOP DEFFO Lionel L. 5


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

File: segment_size2.c
#include<stdio.h>

int main() {
static int mystaticint1;
printf("Hello World\n");
return 0;
}

In the following program, an initialized static variable is added. This means initialized segment
(DATA) size would increase by 4 Bytes.

File: segment_size3.c
#include<stdio.h>

int main() {
static int mystaticint1;
static int mystaticint2 = 100;
printf("Hello World\n");
return 0;
}

In the following program, an initialized global variable is added. This means initialized segment
(DATA) size would increase by 4 Bytes.

File: segment_size4.c
#include<stdio.h>

int myglobalint1 = 500;


int main() {
static int mystaticint1;
static int mystaticint2 = 100;
printf("Hello World\n");
return 0;
}

In the following program, an uninitialized global variable is added. This means uninitialized
segment (BSS) size would increase by 4 Bytes.

File: segment_size5.c
#include<stdio.h>

int myglobalint1 = 500;


int myglobalint2;
int main() {

Proposed by Dr. SOP DEFFO Lionel L. 6


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

static int mystaticint1;


static int mystaticint2 = 100;
printf("Hello World\n");
return 0;
}

Execution Steps
Compilation
Lionel $ gcc segment_size1.c -o segment_size1
Lionel $ gcc segment_size2.c -o segment_size2
Lionel $ gcc segment_size3.c -o segment_size3
Lionel $ gcc segment_size4.c -o segment_size4
Lionel $ gcc segment_size5.c -o segment_size5

Execution/Output
Lionel size segment_size1 segment_size2 segment_size3 segment_size4 segment_size5
text data bss dec hex filename
878 252 8 1138 472 segment_size1
878 252 12 1142 476 segment_size2
878 256 12 1146 47a segment_size3
878 260 12 1150 47e segment_size4
878 260 16 1154 482 segment_size5
Lionel

IV. Process Creation and Termination

Till now we know that whenever we execute a program then a process is created and would be
terminated after the completion of the execution. What if we need to create a process within the
program and may be wanted to schedule a different task for it. Can this be achieved? Yes, obviously
through process creation. Of course, after the job is done it would get terminated automatically or
you can terminate it as needed.
Process creation is achieved through the fork() system call. The newly created process is called the
child process and the process that initiated it (or the process when execution is started) is called the
parent process. After the fork() system call, now we have two processes - parent and child
processes. How to differentiate them? Very simple, it is through their return values.

Proposed by Dr. SOP DEFFO Lionel L. 7


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

After creation of the child process, let us see the fork() system call details.
#include <sys/types.h>
#include <unistd.h>

pid_t fork(void);

Creates the child process. After this call, there are two processes, the existing one is called the
parent process and the newly created one is called the child process.
The fork() system call returns either of the three values −

• Negative value to indicate an error, i.e., unsuccessful in creating the child process.

• Returns a zero for child process.

• Returns a positive value for the parent process. This value is the process ID of the newly
created child process.
Let us consider a simple program.
File name: basicfork.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
fork();
printf("Called fork() system call\n");
return 0;
}

Execution Steps

Compilation
gcc basicfork.c -o basicfork

Execution/Output
Called fork() system call
Called fork() system call

Note − Usually after fork() call, the child process and the parent process would perform different
tasks. If the same task needs to be run, then for each fork() call it would run 2 power n times, where
n is the number of times fork() is invoked.

Proposed by Dr. SOP DEFFO Lionel L. 8


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

In the above case, fork() is called once, hence the output is printed twice (2 power 1). If fork() is
called, say 3 times, then the output would be printed 8 times (2 power 3). If it is called 5 times, then
it prints 32 times and so on and so forth.
Having seen fork() create the child process, it is time to see the details of the parent and the child
processes.

File name: pids_after_fork.c


#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
pid_t pid, mypid, myppid;
pid = getpid();
printf("Before fork: Process id is %d\n", pid);
pid = fork();

if (pid < 0) {
perror("fork() failure\n");
return 1;
}

// Child process
if (pid == 0) {
printf("This is child process\n");
mypid = getpid();
myppid = getppid();
printf("Process id is %d and PPID is %d\n", mypid, myppid);
} else { // Parent process
sleep(2);
printf("This is parent process\n");
mypid = getpid();
myppid = getppid();
printf("Process id is %d and PPID is %d\n", mypid, myppid);
printf("Newly created process id or child pid is %d\n", pid);
}
return 0;
}

Compilation and Execution Steps


Before fork: Process id is 166629
This is child process
Process id is 166630 and PPID is 166629
Before fork: Process id is 166629
This is parent process
Process id is 166629 and PPID is 166628

Proposed by Dr. SOP DEFFO Lionel L. 9


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

Newly created process id or child pid is 166630

A process can terminate in either of the two ways −

• Abnormally, occurs on delivery of certain signals, say terminate signal.

• Normally, using _exit() system call (or _Exit() system call) or exit() library function.
The difference between _exit() and exit() is mainly the cleanup activity. The exit() does some
cleanup before returning the control back to the kernel, while the _exit() (or _Exit()) would return
the control back to the kernel immediately.
Consider the following example program with exit().

File name: atexit_sample.c


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

void exitfunc() {
printf("Called cleanup function - exitfunc()\n");
return;
}

int main() {
atexit(exitfunc);
printf("Hello, World!\n");
exit (0);
}

Note : In the C Programming Language, the atexit function registers a function as a termination
function which is called if the program terminates normally.

When calling the atexit function more than once, the last function to be registered is the first
function that will be called when the program is terminated normally.

Syntax
The syntax for the atexit function in the C Language is:
int atexit(void (*func)(void));

Parameters or Arguments
func
The function to register as a termination function.

Returns
The atexit function returns zero if successful and a nonzero value if unsuccessful

Proposed by Dr. SOP DEFFO Lionel L. 10


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

Compilation and Execution Steps


Hello, World!
Called cleanup function - exitfunc()

Consider the following example program with _exit().

File name: at_exit_sample.c


#include <stdio.h>
#include <unistd.h>

void exitfunc() {
printf("Called cleanup function - exitfunc()\n");
return;
}

int main() {
atexit(exitfunc);
printf("Hello, World!\n");
_exit (0);
}

Compilation and Execution Steps


Hello, World!

V. Child process monitoring

As we have seen, whenever we create a child process from a program using fork, the following
happens −

• Current process now becomes the parent process


• The new process becomes the child process
What happens if the parent process finishes its task early than the child process and then quits or
exits? Now who would be the parent of the child process? The parent of the child process is init
process, which is the very first process initiating all the tasks.
To monitor the child process execution state, to check whether the child process is running or
stopped or to check the execution status, etc. the wait() system calls and its variants is used.
Let us consider an example program, where the parent process does not wait for the child process,
which results into init process becoming the new parent for the child process

#include<stdio.h>

int main() {

Proposed by Dr. SOP DEFFO Lionel L. 11


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

int pid;
pid = fork();

// Child process
if (pid == 0) {
system("ps -ef");
sleep(10);
system("ps -ef");
} else {
sleep(3);
}
return 0;
}

Following are the variants of system calls to monitor the child process/es −

• wait()
• waitpid()
• waitid()
The wait() system call would wait for one of the children to terminate and return its termination
status in the buffer as explained below.
#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *status);

This call returns the process ID of the terminated child on success and -1 on failure. The wait()
system call suspends the execution of the current process and waits indefinitely until one of its
children terminates. The termination status from the child is available in status.
Let us modify the previous program, so that the parent process now waits for the child process.
#include<stdio.h>

int main() {
int pid;
int status;
pid = fork();

// Child process
if (pid == 0) {
system("ps -ef");
sleep(10);
system("ps -ef");
return 3; //exit status is 3 from child process

Proposed by Dr. SOP DEFFO Lionel L. 12


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

} else {
sleep(3);
wait(&status);
printf("In parent process: exit status from child is decimal %d, hexa %0x\n", status, status);
}
return 0;
}

The wait() system call has limitation such as it can only wait until the exit of the next child. If we
need to wait for a specific child it is not possible using wait(), however, it is possible using
waitpid() system call.

The waitpid() system call would wait for specified children to terminate and return its termination
status in the buffer as explained below.
#include <sys/types.h>
#include <sys/wait.h>

pid_t waitpid(pid_t pid, int *status, int options);

The above call returns the process ID of the terminated child on success and -1 on failure. The
waitpid() system call suspends the execution of the current process and waits indefinitely until the
specified children (as per pid value) terminates. The termination status from the child is available in
the status.
The value of pid can be either of the following −

• < -1 − Wait for any child process whose process group ID is equal to the absolute value
of pid.

• -1 − Wait for any child process, which equals to that of wait() system call.

• 0 − Wait for any child process whose process group ID is equal to that of the calling
process.

• >0 − Wait for any child process whose process ID is equal to the value of pid.
By default, waitpid() system call waits only for the terminated children but this default behavior can
be modified using the options argument.
Now let us consider a program as an example, waiting for a specific process with its process id.

/* Filename: waitpid_test.c */
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>

Proposed by Dr. SOP DEFFO Lionel L. 13


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

int main() {
int pid;
int pids[3];
int status;
int numprocesses = 0;
int total_processes = 3;
while (numprocesses < total_processes) {
pid = fork();

// Child process
if (pid == 0) {
printf("In child process: process id is %d\n", getpid());
sleep(5);
return 4;
} else {
pids[numprocesses] = pid;
numprocesses++;
printf("In parent process: created process number: %d\n", pid);
}
}

// Waiting for 3rd child process


waitpid(pids[total_processes - 1], &status, 0);
if (WIFEXITED(status) != 0) {
printf("process %d exited normally\n", pids[total_processes - 1]);
printf("exit status from child is %d\n", WEXITSTATUS(status));
} else {
printf("process %d not exited normally\n", pids[total_processes - 1]);
}
return 0;
}

After compilation and execution, following is the output.

Proposed by Dr. SOP DEFFO Lionel L. 14


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

Now, let us check for waitid() system call. This system call waits for the child process to change
state.
#include <sys/wait.h>

int waitpid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

The above system call waits for the child process to change the state and this call suspends the
current/calling process until any of its child process changes its state. The argument ‘infop’ is to
record the current state of the child. This call returns immediately, if the process has already
changed its state.
The value of idtype can be either of the following −

• P_PID − Wait for any child process whose process ID is equal to that of id.

• P_PGID − Wait for any child process, whose process group ID is equal to that of id.

• P_ALL − Wait for any child process and id is ignored.

• The options argument is to specify which state changes and this can be formed with bitwise
OR operation with the below-mentioned flags −

• WCONTINUED − Returns the status of any child that was stopped and has been continued.

• WEXITED − Waits for the process to exit.

• WNOHANG − Returns immediately.

• WSTOPPED − Waits for the process of any child that has stopped, upon receipt of the
signal and returns the status.
This call returns 0, if it returns due to a change of the state of one of its children and WNOHANG is
used. It returns –1, in case of error and sets the appropriate error number.

/* Filename: waitid_test.c */
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>

int main() {
int pid;
int pids[3];
int status;
int numprocesses = 0;
int total_processes = 3;
siginfo_t siginfo;
while (numprocesses < total_processes) {

Proposed by Dr. SOP DEFFO Lionel L. 15


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

pid = fork();

// Child process
if (pid == 0) {
printf("In child process: process id is %d\n", getpid());
sleep(5);
return 2;
} else {
pids[numprocesses] = pid;
numprocesses++;
printf("In parent process: created process number: %d\n", pid);
}
}

// Waiting for 3rd child process


status = waitid(P_PID, pids[total_processes - 1], &siginfo, WEXITED);
if (status == -1) {
perror("waitid error");
return 1;
}
printf("Info received from waitid is: ");
printf("PID of child: %d, real user id of child: %d\n", siginfo.si_pid, siginfo.si_uid);
return 0;
}

After execution and compilation of the above program, following is the result.

VI. Process groups, sessions and job control

In this section, we will get familiar with Process Groups, Sessions and Job Control.
Process Group − Process group is a collection of one or more processes. A process group
constitutes of one or more processes sharing the same process group identifier (PGID). A process
group ID (PGID) is of the same type (pid_t) as the process ID. A process group has a process group
leader, which is the process that creates the group and whose process ID becomes the process group
ID of the group.

Proposed by Dr. SOP DEFFO Lionel L. 16


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

Sessions − It is a collection of various process groups.


Job Control − This permits a shell user to simultaneously execute multiple commands (or jobs),
one in the foreground and all remaining in the background. It is also possible to move the jobs from
the foreground to the background and vice-versa.
Let us understand this with the help of example program/s using shell (BASH).

• Shell script (in BASH) to perform basic commands (date, echo, sleep and cal) named
basic_commands.sh

• Shell script (in BASH) to perform basic commands (ps, echo)


#!/bin/bash
#basic_commands.sh

date
echo "Now sleeping for 10 seconds, so that testing job control functionality is smooth"
sleep 10
cal

#!/bin/bash
#process_status.sh

ps
echo "Now sleeping for 20 seconds, so that testing job control functionality is smooth"
sleep 20
ps

Use chmod command to give the file the execute permissions. By default, the normal file would get
only read and write permissions and not execute permissions.
To stop the current running process, you need to enter CTRL+Z. This gives you a job number. The
job can be resumed either in the foreground or the background. If needed, to resume the job in the
foreground use ‘fg’ command. If needed, to resume the job in the background, use ‘bg’ command.
By using this, it would run only the last stopped process. What if you want to start other than the
last stopped process? Just use the job number after fg or bg (say bg %2 or bg %3, etc). If the
running job is in the background, you can run any other tasks in the foreground. To get the list of
jobs, use command, jobs. It is also possible to terminate the process either with CTRL+C or kill
command. You can pass the job number while using the kill command.
Check the following output which demonstrates stopping the jobs, moving the jobs from the
foreground to the background and vice versa, terminating the jobs, etc

Proposed by Dr. SOP DEFFO Lionel L. 17


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

VII. Process ressources

The process needs certain resources such as CPU and memory to perform the tasks. Now we will
look into the related commands and system calls to know the information on resource utilization
and monitoring. Also there are certain limits by default for each process on the resources, and if
required the limits can be enhanced to accommodate the application requirements.
Following are the essential system or process resources information using commands −

The top command


$ top

The top command continuously displays the usage of system resources. If any process puts the
system in some kind of hang state (consuming more of CPU or Memory) it is possible to note the
process information and take appropriate action (such as killing the related process).

The ps command
$ ps

The ps command provides information about all the running processes. This helps to monitor and
control the processes.

Proposed by Dr. SOP DEFFO Lionel L. 18


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

The vmstat command


$ vmstat

The vmstat command reports the statistics of virtual memory subsystem. It reports the information
of processes (waiting to run, sleeping, runnable processes, etc.), memory (virtual memory
information such as free, used, etc.), swap area, IO devices, system information (number of
interrupts, context switches) and CPU (user, system and idle time).

The lsof command


$ lsof

The lsof command prints the list of open files of all the current running processes, including system
processes.

The getconf command


$ getconf –a

The getconf command displays the system configuration variables information.


Now, let us take a look at the related system calls.

• System call getrusage(), which provides information on system resource usage.

• System calls related to accessing and setting resource limits viz., getrlimit(), setrlimit(),
prlimit().

System Resource Usage Call


#include <sys/time.h>
#include <sys/resource.h>

int getrusage(int who, struct rusage *usage);

The system call getrusage() returns the information on the system resource usage. This can include
information on self, children, or calling thread using flags RUSAGE_SELF,
RUSAGE_CHILDREN, RUSAGE_THREAD for the “who” variable. After the call, it returns the
information in the structure rusage.
This call would return “0” on success and “-1” on failure.
Let us look at the following sample program.

/* Filename: sysinfo_getrusage.c */
#include<stdio.h>
#include<sys/time.h>
#include<sys/resource.h>

Proposed by Dr. SOP DEFFO Lionel L. 19


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

void main(void) {
struct rusage res_usage;
int retval;
retval = getrusage(RUSAGE_SELF, &res_usage);
if (retval == -1) {
perror("getrusage error");
return;
}
printf("Details of getrusage:\n");
printf("User CPU time (seconds) is %d\n", (int)res_usage.ru_utime.tv_sec);
printf("User CPU time (micro seconds) is %d\n", (int)res_usage.ru_utime.tv_usec);
printf("Maximum size of resident set (kb) is %ld\n", res_usage.ru_maxrss);
printf("Soft page faults (I/O not required) is %ld\n", res_usage.ru_minflt);
printf("Hard page faults (I/O not required) is %ld\n", res_usage.ru_majflt);
printf("Block input operations via file system is %ld\n", res_usage.ru_inblock);
printf("Block output operations via file system is %ld\n", res_usage.ru_oublock);
printf("Voluntary context switches are %ld\n", res_usage.ru_nvcsw);
printf("Involuntary context switches are %ld\n", res_usage.ru_nivcsw);
return;
}

Let us now look at the system calls related to accessing and setting resource limits.
#include <sys/time.h>
#include <sys/resource.h>

int getrlimit(int resource, struct rlimit *rlim);


int setrlimit(int resource, const struct rlimit *rlim);
int prlimit(pid_t pid, int resource, const struct rlimit *new_limit, struct rlimit *old_limit);

The system call getrlimit() gets the resource limits in structure rlimit by inputting the resource one
needs such as RLIMIT_NOFILE, RLIMIT_NPROC, RLIMIT_STACK, etc.
The system call setrlimit() sets the resource limits as mentioned in the rlimit structure as far as
within the limits.

Proposed by Dr. SOP DEFFO Lionel L. 20


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

The system call prlimit() is used for varius purposes, such as either for retrieving the current
resource limits or for updating the resource limits to new values.
The structure rlimit contains two values −

• Soft limit − Current limit

• Hard limit − Maximum limit to which it can be extended.


RLIMIT_NOFILE − Returns the maximum number of file descriptors that can be opened by this
process. For example, if it returns 1024, then the process has file descriptors from 0 to 1023.
RLIMIT_NPROC − Maximum number of processes that can be created for a user of that process.
RLIMIT_STACK − The maximum size in bytes of the stack segment for that process.
All these calls would return “0” on success and “-1” on failure.
Let us consider the following example where we are using getrlimit() system call.

/* Filename: sysinfo_getrlimit.c */
#include<stdio.h>
#include<sys/time.h>
#include<sys/resource.h>

void main(void) {
struct rlimit res_limit;
int retval;
int resources[] = {RLIMIT_NOFILE, RLIMIT_NPROC, RLIMIT_STACK};
int max_res;
int counter = 0;
printf("Details of resource limits for NOFILE, NPROC, STACK are as follows: \n");
max_res = sizeof(resources)/sizeof(int);
while (counter < max_res) {
retval = getrlimit(resources[counter], &res_limit);
if (retval == -1) {
perror("getrlimit error");
return;
}
printf("Soft Limit is %ld\n", res_limit.rlim_cur);
printf("Hard Limit (ceiling) is %ld\n", res_limit.rlim_max);
counter++;
}
return;
}

Proposed by Dr. SOP DEFFO Lionel L. 21


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

Let us consider another example with getrlimit() system call but now with prlimit() system call.

/* Filename: sysinfo_prlimit.c */
#include<stdio.h>
#include<unistd.h>
#include<sys/time.h>
#include<sys/resource.h>

void main(void) {
struct rlimit res_limit;
int retval;
int resources[] = {RLIMIT_NOFILE, RLIMIT_NPROC, RLIMIT_STACK};
int max_res;
int counter = 0;
printf("Details of resource limits for NOFILE, NPROC, STACK using prlimit are as follows: \n");
max_res = sizeof(resources)/sizeof(int);
while (counter < max_res) {
retval = prlimit(getpid(), resources[counter], NULL, &res_limit);
if (retval == -1) {
perror("prlimit error");
return;
}
printf("Soft Limit is %ld\n", res_limit.rlim_cur);
printf("Hard Limit (ceiling) is %ld\n", res_limit.rlim_max);
counter++;
}
return;
}

Proposed by Dr. SOP DEFFO Lionel L. 22


Faculty of Engineering and technologies / computer engineering/ school year 2024-2025

Proposed by Dr. SOP DEFFO Lionel L. 23

You might also like