Download as pdf or txt
Download as pdf or txt
You are on page 1of 21

ASSIGNMENT I

System Calls
The system call provides an interface to the operating system services. Application developers often do not
have direct access to the system calls, but can access them through an application programming interface
(API). The functions that are included in the API invoke the actual system calls. By using the API, certain
benefits can be gained: Portability: as long a system supports an API, any program using that API can compile
and run. Ease of Use: using the API can be significantly easier then using the actual system call.

System Call Parameters


Three general methods exist for passing parameters to the OS:

1. Parameters can be passed in registers.


2. When there are more parameters than registers, parameters can be stored in a block and the block address
can be passed as a parameter to a register. 3. Parameters can also be pushed on or popped off the stack by the
operating system.

Types of System Calls

There are 5 different categories of system calls:

 Process control
A running program needs to be able to stop execution either normally or abnormally. When execution
is stopped abnormally, often a dump of memory is taken and can be examined with a debugger.

 File manipulation
Some common system calls are create, delete, read, write, reposition, or close. Also, there is a need
to determine the file attributes – get and set file attribute. Many times the OS provides an API to
make these system calls.

 Device manipulation
Process usually require several resources to execute, if these resources are available, they will be
granted and control returned to the user process. These resources are also thought of as devices.
Some are physical, such as a video card, and others are abstract, such as a file.

 Information maintenance
Some system calls exist purely for transferring information between the user program and the
operating system. An example of this is time, or date.

 Communication.
There are two models of interprocess communication, the message-passing model and the shared
memory model.
Message-passing uses a common mailbox to pass messages between processes.
Shared memory use certain system calls to create and gain access to create and gain access to
regions of memory owned by other processes. The two processes exchange information by
reading and writing in the shared data.

1
Zombie and Orphan Processes in C

A process which has finished the execution but still has entry in the process table to report to its
parent process is known as a zombie process. A child process always first becomes a zombie before
being removed from the process table. The parent process reads the exit status of the child process
which reaps off the child process entry from the process table.
In the following code, the child finishes its execution using exit() system call while the parent sleeps for
50 seconds, hence doesn’t call wait() and the child process’s entry still exists in the process table.

// A C program to demonstrate Zombie Process.


// Child becomes Zombie as parent is sleeping
// when child process exits.
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
// Fork returns process id
// in parent process
pid_t child_pid = fork();
// Parent process
if (child_pid > 0)
sleep(50);
// Child process
else
exit(0);
return 0;
}

Orphan Process

A process whose parent process no more exists i.e. either finished or terminated without waiting for its
child process to terminate is called an orphan process.
In the following code, parent finishes execution and exits while the child process is still executing and
is called an orphan process now.
However, the orphan process is soon adopted by init process, once its parent process dies.

// A C program to demonstrate Orphan Process.


// Parent process finishes execution while the
// child process is running. The child process
// becomes orphan.
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
// Create a child process
int pid = fork();
if (pid > 0)
printf("in parent process");

2
ASSIGNMENT II
THREAD MANAGEMENT USING PTHREAD LIBRARY

/*
Implement matrix multiplication using multithreading. Application
should
have pthread_create, pthread_join, pthread_exit. In the program, every
thread must return the value and must be collected in pthread_join in
the
main function. Final sum of row-column multiplication must be done by
main
thread (main function).
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define SIZE 10
int A[SIZE][SIZE], B[SIZE][SIZE];
long int C[SIZE][SIZE];
void *mul_thread(void *arg) {
int i, row, col, *rcArgs;
long int return_val; //long int, since int cannot be type casted to
void
rcArgs = (int *) arg;
row = rcArgs[0];
col = rcArgs[1];
i = rcArgs[2];
return_val = A[row][i] * B[i][col];
//return ((void *) return_val);
pthread_exit((void *) return_val);
}
void accept_matrix(int M[SIZE][SIZE], int rows, int cols) {
int i, j;
printf("\n");
for(i=0;i<rows;i++) {
for(j=0;j<cols;j++) {
printf("Value at [%d][%d]: ",i+1,j+1);
scanf("%d",&M[i][j]);
}
}
}
void display_matrix(int M[SIZE][SIZE], int rows, int cols) {
int i, j;
printf("\n");
for(i=0;i<rows;i++){
for(j=0;j<cols;j++){
printf("%2d ",M[i][j]);
}
printf("\n");
}
}
int main() {
int rows_A, cols_A, rows_B, cols_B;
int rcArgs[3];

3
int i, j, k, *status;
pthread_t P[SIZE][SIZE][SIZE];
printf("\nEnter no. of rows in matrix A: ");
scanf("%d",&rows_A);
printf("Enter no. of columns in matrix A: ");
scanf("%d",&cols_A);
accept_matrix(A, rows_A, cols_A);
printf("\nEnter no. of rows in matrix B: ");
scanf("%d",&rows_B);
printf("Enter no. of columns in matrix B: ");
scanf("%d",&cols_B);
accept_matrix(B, rows_B, cols_B);
if(cols_A == rows_B) {
for(i=0;i<rows_A;i++) {
for(j=0;j<cols_B;j++) {
for(k=0;k<cols_A;k++){
rcArgs[0] = i;
rcArgs[1] = j;
rcArgs[2] = k;
//Creating a new thread for every multiplication operation
if(pthread_create(&P[i][j][k], NULL, mul_thread, rcArgs) != 0)
printf("\nCannot create thread.\n");
else
//Inserting delay
sleep(1);
}
}
}
} else {
printf("\n Matrix multiplication not possible.");
exit(1);
}
printf("\nMatrix A:");
display_matrix(A, rows_A, cols_A);
printf("\nMatrix B:");
display_matrix(B, rows_B, cols_B);
for(i=0;i<rows_A;i++) {
for(j=0;j<cols_B;j++) {
for(k=0;k<cols_A;k++){
//joining all the threads and retrieving values in status
if(pthread_join(P[i][j][k],(void **) &status) != 0)
perror("\nThread join failed.\n");
C[i][j] += (long int)status;
}
}
}
printf("\nResultant Matrix:\n");
for(i=0;i<rows_A;i++){
for(j=0;j<cols_B;j++){
printf("%2ld ",C[i][j]);
}
printf("\n");
}
exit(EXIT_SUCCESS);}

4
ASSIGNMENT III
THREAD SYNCHRONIZATION USING COUNTING SEMAPHORES & MUTUAL EXCLUSION USING
MUTEX

#include<stdio.h>
#include<semaphore.h>
#include<sys/types.h>
#include<pthread.h>
#include<unistd.h>
#include<stdlib.h>
#define BUFFER_SIZE 10
pthread_mutex_t mutex;
sem_t empty,full;
int buffer[BUFFER_SIZE];
int counter;
pthread_t tid;
void *producer();
void *consumer();
void insert_item(int);
int remove_item();
void initilize()
{
pthread_mutex_init(&mutex,NULL);
sem_init(&full,0,0);
sem_init(&empty,0,BUFFER_SIZE);
}
void *producer()
{
int item,wait_time;
wait_time=rand()%5;
sleep(wait_time)%5;
item=rand()%10;
sem_wait(&empty);
pthread_mutex_lock(&mutex);
printf("Producer produce %d\n\n",item);
insert_item(item);
pthread_mutex_unlock(&mutex);
sem_post(&full);
}
void *consumer()
{
int item,wait_time;
wait_time=rand()%5;
sleep(wait_time);
sem_wait(&full);
pthread_mutex_lock(&mutex);
item=remove_item();
printf("Consumer consume %d\n\n",item);
pthread_mutex_unlock(&mutex);
sem_post(&empty);
}

5
void insert_item(int item)
{
buffer[counter++]=item;
}
int remove_item()
{
return buffer[--counter];
}
int main()
{
int n1,n2;
int i;
printf("Enter number of Producers");
scanf("%d",&n1);
printf("Enter number of Consumers");
scanf("%d",&n2);
initilize();
for(i=0;i<n1;i++)
pthread_create(&tid,NULL,producer,NULL);
for(i=0;i<n2;i++)
pthread_create(&tid,NULL,consumer,NULL);
sleep(5);
exit(0);
}

// OUTPUT

Enter number of Producers7


Enter number of Consumers6
Producer produce 1
Producer produce 2
Consumer consume 2
Producer produce 6
Producer produce 0
Consumer consume 0
Producer produce 6
Consumer consume 6
Producer produce 2
Producer produce 6
Consumer consume 6
Consumer consume 2
Consumer consume 6

6
ASSIGNMENT IV
DEADLOCK AVOIDANCE USING SEMAPHORES

include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
pthread_t philosopher[5];
pthread_mutex_t spoon[5];
void *func(int n)
{
printf("Philosopher %d is thinking\n",n);
pthread_mutex_lock(&spoon[n]);
pthread_mutex_lock(&spoon[(n+1)%5]);
printf("Philosopher %d is eating\n",n);
sleep(3);
pthread_mutex_unlock(&spoon[n]);
pthread_mutex_unlock(&spoon[n+1]);
printf("Philosopher %d finished eating\n",n);
return(NULL);
}
int main()
{
int i;
for(i=0;i<5;i++)
pthread_mutex_init(&spoon[i],NULL);
for(i=0;i<5;i++)
pthread_create(&philosopher[i],NULL,(void *)func,(void *)i);
for(i=0;i<5;i++)
pthread_join(philosopher[i],NULL);
for(i=0;i<5;i++)
pthread_mutex_destroy(&spoon[i]);
return 0;
}

OUTPUT
Philosopher 0 is thinking
Philosopher 1 is thinking
Philosopher 1 is eating
Philosopher 3 is thinking
Philosopher 3 is eating
Philosopher 4 is thinking
Philosopher 2 is thinking
Philosopher 1 finished eating
Philosopher 0 is eating
Philosopher 3 finished eating
Philosopher 2 is eating
Philosopher 0 finished eating
Philosopher 2 finished eating
Philosopher 4 is eating
Philosopher 4 finished eating

7
ASSIGNMENT V
INTER PROCESS COMMUNICATION ON LINUX

INTRODUCTION TO IPC ON LINUX

Inter-Process-Communication (or IPC for short) are mechanisms provided by the kernel to allow processes to
communicate with each other. On modern systems, IPCs form the web that bind together each process within
a large scale software architecture.

The Linux kernel provides the following IPC mechanisms:

1. Signals
2. Anonymous Pipes
3. Named Pipes or FIFOs
4. SysV Message Queues
5. POSIX Message Queues
6. SysV Shared memory
7. POSIX Shared memory
8. SysV semaphores
9. POSIX semaphores
10. FUTEX locks
11. File-backed and anonymous shared memory using mmap
12. UNIX Domain Sockets
13. Netlink Sockets
14. Network Sockets
15. Inotify mechanisms
16. FUSE subsystem
17. D-Bus subsystem

SIGNALS
Signals are the cheapest forms of IPC provided by Linux. Their primary use is to notify processes of change in
states or events that occur within the kernel or other processes. We use signals in real world to convey
messages with least overhead - think of hand and body gestures. For example, in a crowded gathering, we
raise a hand to gain attention, wave hand at a friend to greet and so on.
On Linux, the kernel notifies a process when an event or state change occurs by interrupting the process's
normal flow of execution and invoking one of the signal handler functinos registered by the process or by the
invoking one of the default signal dispositions supplied by the kernel, for the said event.

ANONYMOUS PIPE
Anonymous pipes (or simply pipes, for short) provide a mechanism for one process to stream data to another.
A pipe has two ends associated with a pair of file descriptors - making it a one-to-one messaging or
communication mechanism. One end of the pipe is the read-end which is associated with a file-descriptor that
can only be read, and the other end is the write-end which is associated with a file descriptor that can only be
written. This design means that pipes are essentially half-duplex.
Anonymous pipes can be setup and used only between processes that share parent-child relationship.
Generally the parent process creates a pipe and then forks child processes. Each child process gets access to
the pipe created by the parent process via the file descriptors that get duplicated into their address space. This
allows the parent to communicate with its children, or the children to communicate with each other using the
shared pipe.

8
NAMED PIPES OR FIFO
Named pipes (or FIFO) are variants of pipe that allow communication between processes that are not related
to each other. The processes communicate using named pipes by opening a special file known as a FIFO file.
One process opens the FIFO file from writing while the other process opens the same file for reading. Thus any
data written by the former process gets streamed through a pipe to the latter process. The FIFO file on disk
acts as the contract between the two processes that wish to communicate.

MESSAGE QUEUES
Message Queues are synonymous to mailboxes. One process writes a message packet on the message queue
and exits. Another process can access the message packet from the same message queue at a latter point in
time. The advantage of message queues over pipes/FIFOs are that the sender (or writer) processes do not have
to wait for the receiver (or reader) processes to connect. Think of communication using pipes as similar to two
people communicating over phone, while message queues are similar to two people communicating using mail
or other messaging services.

There are two standard specifications for message queues.

1. SysV message queues.


The AT&T SysV messa ge queues support message channeling. Each message packet sent by senders carry a
message number.
The receivers can either choose to receive message that match a particular message number, or receive all
other messages excluding a particular message number or all messages.

2. POSIX message queues.


The POSIX message queu es support message priorities. Each message packet sent by the senders carry a
priority number along with the message payload. The messages get ordered based on the priority number in
the message queue. When the receiver tries to read a message at a later point in time, the messages with
higher priority numbers get delivered first. POSIX message queues also support asynchronous message
delivery using threads or signal based notification.

Linux support both of the above standards for message queues.

SHARED MEMORY
As the name implies, this IPC mechanism allows one process to share a region of memory in its address space
with another. This allows two or more processes to communicate data more efficiently amongst themselves
with minimal kernel intervention.

There are two standard specifications for Shared memory.

1. SysV Shared memory.


Many applications even today use this mechanism for historical reasons. It follows some of the
artifacts of SysV IPC semantics.
2. POSIX Shared memory.
The POSIX specifications provide a more elegant approach towards implementing shared memory
interface. On Linux, POSIX Shared memory is actually implemented by using files backed by RAM-
based filesystem. I recommend using this mechanism over the SysV semantics due to a more elegant
file based semantics.

SEMAPHORES
Semaphores are locking and synchronization mechanism used most widely when processes share resources.
Linux supports both SysV semaphores and POSIX semaphores. POSIX semaphores provide a more simpler and
elegant implementation and thus is most widely used when compared to SysV semaphores on Linux.

9
FUTEXES
Futexes are high-performance low-overhead locking mechanisms provided by the kernel. Direct use of futexes
is highly discouraged in system programs. Futexes are used internally by POSIX threading API for condition
variables and its mutex implementations.

UNIX DOMAIN SOCKETS


UNIX Domain Sockets provide a mechanism for implementing applications that communicate using the Client-
Server architecture.They support both stream and datagram oriented communication, are full-duplex and
support a variety of options. They are very widely used for developing many large-scale frameworks.

NETLINK SOCKETS
Netlink sockets are similar to UNIX Domain Sockets in its API semantics - but used mainly for two purposes:
For communication between a process in user-space to a thread in kernel-space
For communication amongst processes in user-space using broadcast mode.

NETWORK SOCKETS
Based on the same API semantics like UNIX Domain Sockets, Network Sockets API provide mechanisms for
communication between processes that run on different hosts on a network. Linux has rich support for
features and various protocol stacks for using network sockets API. For all kinds of network programming and
distributed programming - network socket APIs form the core interface.

INOTIFY MECHANISMS
The Inotify API on Linux provides a method for processes to know of any changes on a monitored file or a
directory asynchronously. By adding a file to inotify watch-list, a process will be notified by the kernel on any
changes to the file like open, read, write, changes to file stat, deleting a file and so on.

FUSE SUBSYSTEM
FUSE provides a method to implement a fully functional filesystem in user-space. Various operations on the
mounted FUSE filesystem would trigger functions registered by the user-space filesystem handler process. This
technique can also be used as an IPC mechanism to implement Client-Server architecture without using socket
API semantics.

D-BUS SUBSYSTEM
D-Bus is a high-level IPC mechanism built generally on top of socket API that provides a mechanism for
multiple processes to communicate with each other using various messaging patterns. D-Bus is a standards
specification for processes communicating with each other and very widely used today by GUI
implementations on Linux following Freedesktop.org specifications.

10
ASSIGNMENT VI
LINUX KERNAL CONFIGURATION

Kernel Configuration

The configuration of the current kernel is stored in the file /proc/config.gz. To modify this configuration, go to
the directory /usr/src/linux as root and execute the following commands:
zcat /proc/config.gz > .config
make oldconfig
The command make oldconfig uses the file /usr/src/linux/.config as a template for the current kernel
configuration. Any new options for your current kernel sources will be queried. If the file .config does not exist,
the default configuration included in the kernel sources will be used.

Configuration on the Command Line

To configure the kernel, change to /usr/src/linux and enter the command make config. Choose the features
you want supported by the kernel. Usually, There are two or three options: y , n , or m . m means that this
device will not be compiled directly into the kernel, but loaded as a module. Drivers needed for booting the
system must be integrated into the kernel with y . Press Enter to confirm the default settings read from the
file .config. Press any other key to view a brief help text about the respective option.

Configuration in Text Mode

“menuconfig” is a more comfortable way to configure the kernel. If necessary, install ncurses-devel with YaST.
Start the kernel configuration with the command make menuconfig.
For minor changes in the configuration, you do not have to go through all the questions. Instead, use the menu
to
access certain sections directly. The default settings are loaded from the file .config. To load a different
configuration, select ‘Load an Alternate Configuration File’ and enter the file name.

Configuration in the X Window System

If you installed and configured the X Window System (package xf86) and Tcl/Tk (tcl and tk), you can use the
command make xconfig to access a graphical user interface for the configuration. If you are not logged in to
the
X Window System as root, enter the command xhost + to give root access to the display. The default settings
will be loaded from the file .config. As the configuration with make xconfig is not as well maintained as the
other configuration possibilities, run the command make oldconfig after using this configuration method.

11
ASSIGNMENT VII
KERNAL SPACE PROGRAMMING

Implementing and adding a loadable kernel module to Linux kernel, demonstrate using
insmod, lsmod and rmmod commands. A sample kernel space program will print the "Hello
World" while loading the kernel module and "Goodbye World" while unloading the kernel
module.

//Save these files in one folder


//Program: hello.c

#include
#include
#include

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Nitish Raj");
MODULE_DESCRIPTION("This is a simple kernel program ");
static int myinit(void)
{
printk(KERN_INFO,"HELLO WORKD\n");
return 0;
}

static void mycleanup(void)


{
printk(KERN_INFO,"GOOD BYE");
}

module_init(myinit);
module_exit(mycleanup);

//Makefile.txt

obj-m += hello.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

//OUTPUT

Nitish@Nitish-Lenovo-Z51-70:~/Desktop/os/7$ make
make -C /lib/modules/4.4.0-72-generic/build M=/home/Nitish/Desktop/os/7
modules
make[1]: Entering directory '/usr/src/linux-headers-4.4.0-72-generic'
CC [M] /home/Nitish/Desktop/os/7/hello.o
In file included from include/linux/printk.h:6:0,
from include/linux/kernel.h:13,
from /home/Nitish/Desktop/os/7/hello.c:1:
/home/Nitish/Desktop/os/7/hello.c: In function ‘myinit’:
include/linux/kern_levels.h:4:18: warning: too many arguments for format [-
Wformat-extra-args]
#define KERN_SOH "\001" /* ASCII Start Of Header */

12
^
include/linux/kern_levels.h:13:19: note: in expansion of macro ‘KERN_SOH’
#define KERN_INFO KERN_SOH "6" /* informational */
^
/home/Nitish/Desktop/os/7/hello.c:11:9: note: in expansion of macro
‘KERN_INFO’
printk(KERN_INFO,"HELLO WORKD\n");
^
/home/Nitish/Desktop/os/7/hello.c: In function ‘mycleanup’:
include/linux/kern_levels.h:4:18: warning: too many arguments for format [-
Wformat-extra-args]
#define KERN_SOH "\001" /* ASCII Start Of Header */
^
include/linux/kern_levels.h:13:19: note: in expansion of macro ‘KERN_SOH’
#define KERN_INFO KERN_SOH "6" /* informational */
^
/home/Nitish/Desktop/os/7/hello.c:17:9: note: in expansion of macro
‘KERN_INFO’
printk(KERN_INFO,"GOOD BYE");
^
Building modules, stage 2.
MODPOST 1 modules
CC /home/Nitish/Desktop/os/7/hello.mod.o
LD [M] /home/Nitish/Desktop/os/7/hello.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.4.0-72-generic'

Nitish@Nitish-Lenovo-Z51-70:~/Desktop/os/7$sudo insmod hello.ko

Nitish@Nitish-Lenovo-Z51-70:~/Desktop/os/7$sudo dmesg | tail -1

Nitish@Nitish-Lenovo-Z51-70:~/Desktop/os/7$sudo lsmod

Nitish@Nitish-Lenovo-Z51-70:~/Desktop/os/7$sudo rmmod hello

Nitish@Nitish-Lenovo-Z51-70:~/Desktop/os/7$sudo dmesg | tail -1

13
ASSIGNMENT VIII
IMPLEMENTATION OF THE SYSTEM CALL

For consistency sake, I suggest using a compiled kernel version of 4.7.1 if you’re following this guide
meticulously line by line.
Henceforth, it is assumed that you’re done with compiling your Linux Kernel from source with the kernel
version of your choice, you know the location of the compiled/extracted kernel source directory, and have
successfully booted into the said version from your grub bootloader.
Now switch into the compiled source directory, eg: cd linux-4.7.1/
Note: The location of this source directory varies with respect to the location you’ve extracted and compiled
your kernel

Define a new System Call, sys_hello()

Create a new directory, mkdir hello and change into the said directory by cd hello Consequently, create a new
C file in this directory in order to add the definition of our system call by nano hello.c (I’m using the nano
editor, while you can use any text editor of your choice).

Add the following code to your new C file


#include <linux/kernel.h>
asmlinkage long sys_hello(void) {
printk(“Hello, world!\n”);
return 0;
}

Note that here printk("...") is a kernel exclusive function that prints to the kernel’s log file, which can be
accessed by the command dmesg

Add the hello directory to the kernel’s Makefile

Similarly, create a new Makefile in the same folder by nano Makefile with the following line obj-y := hello.o
This Makefile specifies the objects to be built and added to the source during the next kernel recompilation.
But before that could happen, we need to make sure that the parent Makefile points to this directory. So let’s
switch back to the previous directory by cd .. which will take us back to the linux-4.7.1/ directory. Now we shall
edit the parent Makefile by nano Makefile

Here we should look for the line that goes like


core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
and append the hello/ directory to the variable so it looks like
core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ hello/

14
This amendment will tell the compiler that the source files of our new system call sys_hello() are present in the
hello/ directory.
So to recap, the compiler’s flow during a sudo make will look something like — Makefile is executed and since
the hello/ directory is now listed, it will search for another Makefile in the said directory for further
instructions about which objects to compile.

Add the new system call into the System Call table
Since I’m working on a 64-bit system, I will have to alter the syscall_64.tbl file.
To do this, I edit the table by nano arch/x86/entry/syscalls/syscall_64.tbl and scroll down till I find the number
of the last system call before those starting from 512.

15
In my case, that’s 328. So my new System Call’s number should be 329.
Now add the line 329 64 hello sys_hello after the 328th System Call to provision our newly created System
Call. Remember this number 329 cause we’ll need it in a few minutes.

Add the new System Call in the System Call header file

Now head back to the source directory linux-4.7.1 and change directories with cd include/linux/ Furthermore,
nano syscalls.h and add the line asmlinkage long sys_hello(void); at the end of the file just before the #endif
statement.

This defines the prototype of the function of our System Call. asmlinkage is a keyword used to indicate that all
parameters of the function would be available on the stack.

Recompile the kernel


Switch over to the source directory linux-4.7.1/ and execute the following command sudo make -j4
modules_install install and watch your terminal throw a bunch of INSTALL lines till you reach a successful quiet
completion.
For the system to now use the newly configured kernel, reboot.

16
Test the System Call
Like we did previously, create a C program in your home folder by nano userspace.c and add the following
code

#include <stdio.h>
#include <linux/kernel.h>
#include <sys/syscall.h>
#include <unistd.h>
int main() {
long int shoutout = syscall(329);
printf(“System call sys_hello returned %ld\n”, shoutout);
return 0;
}

Note that this is where you’ll need to use the number of the newly created System Call — 329.
Finally, let’s compile the program using gcc userspace.c and given that there are no errors during this
compilation, run the said program using ./a.out
If all steps were followed correctly, System call sys_hello returned 0 gets printed onto the console. If it shows -
1 instead of 0, then something’s wrong so you’d have to go back, debug and try again.

Since earlier we used the kernel function


printk("...") that prints to the kernel’s log,
we shall enter dmesg to check if the
message has been sucessfully printed.

17
ASSIGNMENT IX
IMPLEMENTING A CPU SCHEDULING POLICY IN A LINUX OS

/*
Program to implement the sheduling using the FCFS Algorithm,SJF
Algorithm,Round Robin Algorithm:
*/

#include<stdio.h>
#include<stdlib.h>
struct templet
{
char name[8];
int at,st,pt,ft,tat,wt,priority,remain,flag;
}p[20],temp;

void fcfs();
void sjf();
void rr();
int main()
{
int ch;
do{
printf("\n\t1.FCFS\t2.SJF\t3.Round Robin\t4.exit");
printf("\n\tEnter choice : ");
scanf("%d",&ch);
switch(ch)
{
case 1:
fcfs();
break;
case 2:
sjf();
break;
case 3:
rr();
break;
}}while(ch!=4);
}
void fcfs()
{
int no,i,j,fcnt=0,scnt=0;
printf("\n\tEnter no of processes : ");
scanf("%d",&no);
for(i=0;i<no;i++)
{
printf("\n\tEnter process name : ");
scanf("%s",p[i].name);
printf("\n\tEnter Burst time : ");
scanf("%d",&p[i].pt);
}
printf("\n\t Grant Chart : \n\t\t");
for(i=0;i<no;i++)
{
p[i].st=fcnt;
fcnt+=p[i].pt;
p[i].wt=fcnt-p[i].pt;
p[i].tat=fcnt;
printf("%s -->",p[i].name);

18
}
printf("Finish");
fcnt=0;
printf("\n\tProcess \t burst time \t waiting time \t turn around
time");
for(i=0;i<no;i++)
{
printf("\n\t%s\t\t\t%d\t\t%d\t
\t%d",p[i].name,p[i].pt,p[i].wt,p[i].tat);
fcnt+=p[i].wt;
scnt+=p[i].tat;
}
printf("\n\n\t\t\t\tAverage : \t %d\t \t%d",fcnt/no,scnt/no);
}
void sjf()
{
int no,i,j,fcnt=0,scnt=0;
printf("\n\tEnter no of processes : ");
scanf("%d",&no);
for(i=0;i<no;i++)
{
printf("\n\tEnter process name : ");
scanf("%s",p[i].name);
printf("\n\t Enter Arrival time : ");
scanf("%d",&p[i].at);
printf("\n\tEnter Burst time : ");
scanf("%d",&p[i].pt);
p[i].remain=p[i].pt;
p[i].flag=0;
}
for(i=0;i<no;i++)
{
for(j=0;j<no;j++)
{
if(p[i].at<p[j].at)
{
temp=p[i];
p[i]=p[j];
p[j]=temp;
}
}
}
i=0;
scnt=p[i].at;
while(1)
{
if(p[i].flag==0)
{
p[i].remain--;
scnt++;
if(p[i].remain>0)
{
for(j=0;j<no;j++)
{
if(p[j].at<=scnt && p[j].flag==0)
{
if(p[i].remain>p[j].remain)
{
i=j;
}
}

19
}
}
else
{
p[i].wt=scnt-p[i].pt-p[i].at;
p[i].tat=scnt-p[i].at;
p[i].flag=1;
fcnt++;

if(fcnt==no)
break;
if(i<no-1)
i++;
else
i=0;
for(j=i;j>0;j--)
if(p[j].remain < p[i].remain && p[j].flag==0)
i=j;
}
}
else
i++;
}
fcnt=0,scnt=0;
printf("\n\tProcess \t burst time \t waiting time \t turn around
time");
for(i=0;i<no;i++)
{
printf("\n\t%s\t\t\t%d\t\t%d\t
\t%d",p[i].name,p[i].pt,p[i].wt,p[i].tat);
fcnt+=p[i].wt;
scnt+=p[i].tat;
}
printf("\n\n\t\t\t\tAverage : \t %d\t \t%d",fcnt/no,scnt/no);
}
void rr()
{
int no,i,j,fcnt=0,scnt=0,interval;
printf("\n\tEnter no of processes : ");
scanf("%d",&no);
for(i=0;i<no;i++)
{
printf("\n\tEnter process name : ");
scanf("%s",p[i].name);
printf("\n\tEnter Burst time : ");
scanf("%d",&p[i].pt);
p[i].remain=p[i].pt;
p[i].flag=0;
}
printf("\n\t Enter interval : ");
scanf("%d",&interval);

printf("\n\t Grant Chart : \n\t\t");

i=0;
while(1)
{
for(i=0;i<no;i++)
{
if(p[i].flag==0)
{

20
if(p[i].remain<=interval)
{
//printf("-- %s (C)--",p[i].name);
scnt+=p[i].remain;
p[i].wt=scnt-p[i].pt;
p[i].tat=scnt;
p[i].flag=1;
fcnt++;
}
else
{
//printf("-- %s --",p[i].name);
p[i].remain-=interval;
scnt+=interval;
}
}
}
if(fcnt==no)
break;
}

printf("Finish");
fcnt=0,scnt=0;
printf("\n\tProcess \t burst time \t waiting time \t turn around
time");
for(i=0;i<no;i++)
{
printf("\n\t%s\t\t\t%d\t\t%d\t
\t%d",p[i].name,p[i].pt,p[i].wt,p[i].tat);
fcnt+=p[i].wt;
scnt+=p[i].tat;
}
printf("\n\n\t\t\t\tAverage : \t %d\t \t%d\n\n",fcnt/no,scnt/no);
}

21

You might also like