0% found this document useful (0 votes)
529 views45 pages

System Programming & Operating System: A Laboratory Manual FOR

Uploaded by

Shubham
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)
529 views45 pages

System Programming & Operating System: A Laboratory Manual FOR

Uploaded by

Shubham
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/ 45

Name:

Roll No.: Class: TE EnTC


Exam Seat No.:
Academic Year: 2020-21

A LABORATORY MANUAL
FOR
SYSTEM PROGRAMMING & OPERATING
SYSTEM

Dr. D. Y. Patil Educational Enterprises Charitable Trust’s


Dr. D. Y. PATIL SCHOOL OF ENGINEERING
Dr. D. Y. Patil Technical Campus
Dr. D. Y. Patil Knowledge City, Charholi (Bk), Via Lohegaon, Pune 412105

AS PER SAVITRIBAI PHULE PUNE UNIVERSITY (SPPU) SYLLABUS (2019 PATTERN)


SPOS Lab (TE EnTC, 2015 Course) A.Y. 2020-21 Laboratory Manual
______________________________________________________________________________________________________________________

Dr. D. Y. Patil Technical Campus

Dr. D. Y. Patil School of Engineering


Dr. D. Y. Patil Knowledge City, Charholi (Bk), Lohegaon, Pune – 412105
Website: www.dypic.in Contact No.:020-6707 7926

Department of Electronics & Telecommunication (SE)

System Programming & Operating System


Lab
(T.E. EnTC 2015 Course)

LABORATORY MANUAL

Prepared By
Prof. Faraz Bagwan
(Subject Teacher)

_______________________________________________________________________________________________________________________
SPOS Lab (TE EnTC, 2015 Course) A.Y. 2020-21 Laboratory Manual
______________________________________________________________________________________________________________________

Course Objectives:
• To understand system software concepts, like the use and implementation of assembler, macros,
linker, loaders and compiler.
• To get acquainted with software tools for program development.
• To explore memory allocation methods, input output devices and file system w. r. t. various
operating system.
• To study and implement various processes scheduling techniques and dead lock avoidance schemes
in operating system.

Course Outcomes:
CO1: On completion of the course, student will be able to
CO2: Demonstrate the knowledge of Systems Programming and Operating Systems
CO3: Formulate the Problem and develop the solution for same.
CO4: Compare and analyse the different implementation approach of system programming
operating system abstractions.
CO5: Interpret various OS functions used in Linux / Ubuntu

List of Experiments to perform

1.a. Study of Basic Linux Commands


b. Write an shell scripting on LINUX OS
2. Write C Program to implement Lexical Analyzer for simple arithmetic operation which
creates output tables (Uniform Symbol Table or a. Identifier Table b. Literal Table c. Symbol
Table)
3. Design of PASS I of two pass assembler for pseudo machine code.
4. Design of a MACRO PASS-I
5. Implement Job scheduling algorithms: FCFS, SJF
6. Implement Bankers Algorithm for deadlock detection and avoidance
7. Implementation of page replacement algorithm: FIFO / LRU
8. Case Study
a. Android mobile operating system
b. Study of System calls to list files, directories
c. Study of System calls to handles process

_______________________________________________________________________________________________________________________
Department of EnTC Engineering (SE) Dr. D. Y. Patil School of Engineering, Lohegaon, Pune
Programming & Problem Solving (FE, 2015 Course), A.Y. 2018-19 Laboratory Manual
______________________________________________________________________________________________________________________

Dr. D. Y. Patil Technical Campus

Dr. D. Y. Patil School of Engineering


Dr. D. Y. Patil Knowledge City, Charholi (Bk), Lohegaon, Pune – 412 105
Website: www.dypic.in Contact No.:020-6707 7926

Department of EnTC Engineering (SE)

INDEX
Exp. Title of Experiment DoP DoA Remark/ Sign
No. Marks
1 a. Study of Basic Linux Commands 2-2-21 5-2-21
b. Write a shell scripting on LINUX OS
2 Write C Program to implement Lexical 16-2-21 19-2-21
Analyzer for simple arithmetic operation
3 Design of PASS I & Pass II assembler for 8-3-21 12-3-21
pseudo machine code.
4 Design of a MACRO PASS-I 23-3-21 26-3-21
5 Implement Job scheduling algorithms: FCFS, 5-4-21 9-4-21
SJF
6 Implement Bankers Algorithm for deadlock 19-4-21 23-4-21
detection and avoidance
7 Implementation of page replacement 10-5-21 14-5-21
algorithm: FIFO
8.a Study of System calls to list files, directories 8-6-21 11-6-21
8.b Study of System calls to handles process 24-5-21 28-5-21

CERTIFICATE

This is to certify that Mr. / Ms: _____________________________________________________

Class: TE EnTC Roll No. ________ University Exam Seat No. _________________________ has

completed all the practical work satisfactorily in the subject of Sys Prog. & OS Lab as

prescribed by the Savitribai Phule Pune University (SPPU).

Date:__________________ Academic Year: 2020-21

Faraz Bagwan Dr. Sanjay Koli Dr. Ashok Kasnale


Sub. In-Charge Head of Department Principal
_______________________________________________________________________________________________________________________
Department of EnTC Engineering (SE) Dr. D. Y. Patil School of Engineering, Lohegaon, Pune
EXPERIMENT NO: 1.a

TITLE: Study of Basic Linux Commands

THEORY:

Basic Linux/Unix Commands with Examples and Syntax


File Management becomes easy if you know the right basic command in Linux.
Sometimes, commands are also referred as "programs" since whenever you run a command,
it's the corresponding program code, written for the command, which is being executed.

Listing files (ls)


If you want to see the list of files on your UNIX or Linux system, use the 'ls' command.

It shows the files /directories in your current directory.

Note:
• Directories are denoted in blue color.
• Files are denoted in white.
• You will find similar color schemes in different flavors of Linux.

Creating & Viewing Files


The 'cat' server command is used to display text files. It can also be used for copying,
combining and creating new text files. Let's see how it works.
To create a new file, use the command
1. cat > filename
2. Add content
3. Press 'ctrl + d' to return to command prompt.
How to create and view files in Linux/Unix
To view a file, use the command -
cat filename
Let's see the file we just created -
Let's see another file sample2

The syntax to combine 2 files is -


cat file1 file2 > newfilename
Let's combine sample 1 and sample 2.

As soon as you insert this command and hit enter, the files are concatenated, but you do not
see a result. This is because Bash Shell (Terminal) is silent type. Shell Commands will
never give you a confirmation message like "OK" or "Command Successfully Executed". It will
only show a message when something goes wrong or when an error has occurred.
To view the new combo file "sample" use the command
cat sample

Note: Only text files can be displayed and combined using this command.

Creating Directories
Directories can be created on a Linux operating system using the following command
This command will create a subdirectory in your present working directory, which is usually
your "Home Directory".

The History Command


History command shows all the basic commands in Linux that you have used in the past for
the current terminal session. This can help you refer to the old commands you have entered
and re-used them in your operations again.

CONCLUSION:
Thus, we have successfully implemented basic Linux commands.
EXPERIMENT NO: 1.b

TITLE: Write C Program to implement Lexical Analyzer for simple arithmetic operation
which creates output tables (Uniform Symbol Table or a. Identifier Table b. Literal Table
c. Symbol Table)

THEORY:

A shell script is a computer program designed to be run by the Unix/Linux shell which could
be one of the following:
• The Bourne Shell
• The C Shell
• The Korn Shell
• The GNU Bourne-Again Shell
A shell is a command-line interpreter and typical operations performed by shell scripts include
file manipulation, program execution, and printing text.

Extended Shell Scripts


Shell scripts have several required constructs that tell the shell environment what to do and
when to do it. Of course, most scripts are more complex than the above one.
The shell is, after all, a real programming language, complete with variables, control
structures, and so forth. No matter how complicated a script gets, it is still just a list of
commands executed sequentially.

ALGORITHM:
1. Get a number
2. Use for loop or while loop to compute the factorial by using the below formula
3. fact(n) = n * n-1 * n-2 * .. 1
4. Display the result.

OUTPUT:

CONCLUSION:

Thus, we have successfully implemented a shell script for calculating factorial of a number.
EXPERIMENT NO: 2

TITLE: Write C Program to implement Lexical Analyzer for simple arithmetic operation
which creates output tables (Uniform Symbol Table or a. Identifier Table b. Literal Table
c. Symbol Table)

THEORY:

Compiler is responsible for converting high level language in machine language. There are
several phases involved in this and lexical analysis is the first phase.
Lexical analyzer reads the characters from source code and convert it into tokens.

Different tokens or lexemes are:


• Keywords
• Identifiers
• Operators
• Constants

Take below example.


c = a + b;

After lexical analysis a symbol table is generated as given below.

Token Type

c identifier

= operator

a identifier

+ operator

b identifier

; separator
SOURCE CODE:

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

int isKeyword(char buffer[]){


char keywords[32][10] =
{"auto","break","case","char","const","continue","default",
"do","double","else","enum","extern","float","for","goto",
"if","int","long","register","return","short","signed",
"sizeof","static","struct","switch","typedef","union",
"unsigned","void","volatile","while"};
int i, flag = 0;
for(i = 0; i < 32; ++i){
if(strcmp(keywords[i], buffer) == 0){
flag = 1;
break;
}
}
return flag;
}

int main(){
char ch, buffer[15], operators[] = "+-*/%=";
FILE *fp;
int i,j=0;
fp = fopen("program.txt","r");
if(fp == NULL){
printf("error while opening the file\n");
exit(0);
}
while((ch = fgetc(fp)) != EOF){
for(i = 0; i < 6; ++i){
if(ch == operators[i])
printf("%c is operator\n", ch);
}

if(isalnum(ch)){
buffer[j++] = ch;
}
else if((ch == ' ' || ch == '\n') && (j != 0)){
buffer[j] = '\0';
j = 0;

if(isKeyword(buffer) == 1)
printf("%s is keyword\n", buffer);
else
printf("%s is indentifier\n", buffer);
}
}
fclose(fp);
//system("PAUSE");
return 0;
}

OUTPUT:

CONCLUSION:

Thus, we have successfully implemented lexical Analyzer in C


EXPERIMENT NO: 3

TITLE: Design of PASS I & II assembler for pseudo machine code.

THEORY:

## What is an Assembler?

Assembler is a program for converting instructions that are written in low-level assembly code
into relocatable machine code and generating information along, for the loader.

## What is a Single Pass Assembler?

It is an assembler that generates the object code directly in memory for immediate execution.
It passes through your source code only once and then it’s done. It generates instructions
by evaluating the mnemonics in operation field and finds the value of symbol and literals to
produce machine code.

## What is a Two-Pass assembler?

When an assembler divides its tasks in two passes, it is called a Two-pass assembler.

- Pass-1:

1. Defines symbols and literals and remembers them in symbolic table form and literal
table form respectively.
2. Keep track of location counter.
3. Process pseudo-operations.

- Pass-2:

1. Generate object code by converting symbolic op-code into corresponding numeric op-
code.
2. Generate data for literals and look for values of symbols.

## Why do we need a Two-pass assembler?

One-pass assembler cannot resolve issues of forward references of data symbols. It requires
all data symbols to be defined before they are being used. A Two-pass assembler solves this
confusion by devoting one pass exclusively to resolve all issues of forward referencing and
then generates object code with no chaos in the next pass.

# Algorithm Design

In our design of a Two-pass assembler, we are interested in generating machine codes from a
given set of assembly language codes. Tasks performed by the assembler in the two passes
are:
Pass 1: Define symbols and literals.

- The length of machine instructions would be determined.


- The track of location counter (LC) would be kept.
- Symbol values must be remembered until pass 2.
- Some pseudo-ops, if present in the card, would be processed.
- The literals, if present in the card, would be remembered.

Pass 2: Generate object program

The second pass reads the program again from the beginning. Each instruction is translated
into the appropriate binary machine code. Translation includes the following operations:

- Read operation from the remembered symbol values.


- Generate Instructions.
- Data for DS, DC and literals would be generated.
- Remaining pseudo-ops which remained unprocessed from pass 1 would be processed.

After studying the tasks classification for the two passes, it is necessary to establish a
database that will work with our assembler.

Pass 1 Database

- Input source program.


- A Location Counter for keeping the track of instruction’s location.
- A Machine Operation Table for indicating the symbolic mnemonic for each
instruction and its length.
- A Pseudo-Operation table for indicating the symbolic mnemonic for each
pseudo-op in Pass 1.
- A Symbol Table to store label and its value.
- A Literal Table to store literal and assigned location.
- A copy of input source file to be used in pass 2 can be stored as a File pointer.

Pass 2 Database

- Copy of Input Source Program in pass 1.


- Location counter.
- A Machine-Operation Table (MOT) that indicates Symbolic mnemonic, Length,
Binary machine op-code & format (RS, RX, SI).
- A Pseudo-Operation Table (PoT) that indicates symbolic mnemonic and action
to be taken for each pseudo-op.
- A Symbol Table (SYMTAB) which is prepared during pass 1 containing each
label and its value.
- A Base Table indicates the registers which are currently specified as base
register by USING pseudo-op and its contents.
- A workspace which is used to hold each instruction as its various parts (eg.
Binary op-code, register fields, length fields, displacement fields) are being
assembled.
- A workspace, PRINT, used to produce a printed listing.
- A workspace, PUNCH CARD, used prior to actual outputting for converting the
assembled instruction into a format suitable for loader.
- An output program in a format suitable for the loader.

SOURCE CODE:

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

struct Opcode //This node is used for Hashing using


Chaining
{
char name[10];
char code[35];
char format[5];
struct Opcode *next;
};
struct Symbol //Symbol Table is made using Linked List
to save space
{
char name[50];
int add;
struct Symbol *next;
};
typedef struct Opcode Opcode;
typedef struct Symbol Symbol;

Symbol *head=NULL;

Opcode* hash_table[13] = {NULL};


void reverseArray(int arr[], int start, int end)
{
int temp;
while (start < end)
{
temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
start++;
end--;
}
}
int* conBin(int num) //function to convert in binary
{
int t;
int i, j;
int *bin;
bin=(int*)malloc(10*sizeof(int));
for(i=0; i<10; i++)
{
bin[i]=0;
}
i=9;
t = num;
while(t!=0)
{
bin[i--]= t % 2;
t = t / 2;
}
return bin;
}

char* convertTo5BitBinaryString(int decimal) //This decimal is


between 0 and 31
{
printf("bitbinary function receives %d\n",decimal);
char *str = (char *)malloc(5*sizeof(char));
int d[5]={0};
int i=0,j=0;
while(decimal>0)
{
d[i]=decimal%2;
i++;
decimal=decimal/2;
}
int size = i;
int k=0;
int s=0;

reverseArray(d,0,4);
for(s=0;s<5;s++)
{
printf("%d",d[s]);
str[s] = d[s] + '0';
}
printf("\n");

printf("%s",str);
return str;

}
/*******************************************************************
HASH TABLE IS USED TO STORE THE OPCODES BEING READ
*******************************************************************/
int getHashIndex(char name[])
{
int sum=0,i=0;
while(name[i]!='\0')
{
sum+=name[i++];
}
return sum%13;
}
void insertAtIndex(Opcode *Node,int index)
{
if(hash_table[index] == NULL) //boundary condition
{
hash_table[index] = Node;
Node->next = NULL;
}
else
{
Opcode* temp = hash_table[index];
while(temp->next != NULL)
{
temp = temp->next;
}
temp->next = Node;
Node->next=NULL;
}
}
void insertIntoHashMap(Opcode *Node)
{
int index = getHashIndex(Node->name);
insertAtIndex(Node,index);
}
int *getAddressCode(char* temp)
{
Symbol * t = head;
int * val;
int num;
while(t != NULL)
{
if(!strcmp(temp,t->name))
{
num = t->add;
break;
}
t = t->next;
}
val = conBin(num);
return val;
}
char * getRegisterCode(char* temp)
{
char *s;
if (strcmp(temp,"R0") == 0)
{
s = "00000";
}
else if (strcmp(temp,"R1") == 0)
s = "00001";
else if (strcmp(temp,"R2") == 0)
s = "00010";
else if (strcmp(temp,"R3") == 0)
s = "00011";
else if (strcmp(temp,"R4") == 0)
s = "00100";
else if (strcmp(temp,"R5") == 0)
s = "00101";
else if (strcmp(temp,"R6") == 0)
s = "00110";
else if (strcmp(temp,"R7") == 0)
s = "00111";
else if (strcmp(temp,"R8") == 0)
s = "01000";
else if (strcmp(temp,"R9") == 0)
s = "01001";
else if (strcmp(temp,"R10") == 0)
s = "01010";
else if (strcmp(temp,"R11") == 0)
s = "01011";
else if (strcmp(temp,"R12") == 0)
s = "01100";
else if (strcmp(temp,"R13") == 0)
s = "01101";
else if (strcmp(temp,"R14") == 0)
s = "01110";
else if (strcmp(temp,"R15") == 0)
s = "01111";
else if (strcmp(temp,"A1") == 0)
s = "10000";
else if (strcmp(temp,"A2") == 0)
s = "10001";
else if (strcmp(temp,"A3") == 0)
s = "10010";
else if (strcmp(temp,"A4") == 0)
s = "10011";
else if (strcmp(temp,"port0") == 0)
s = "10100";
else if (strcmp(temp,"port1") == 0)
s = "10101";
return s;
}
char *getConstantCode(int temp)
{
return convertTo5BitBinaryString(temp);
}
struct Opcode* getOpcodeNode(char *op)
{
Opcode* temp = NULL;
int index = getHashIndex(op); //get hash-index for the opcode in
the hash table
if(hash_table[index] == NULL)
{
printf("Wrong Opcode");
return NULL;
}

else
{
temp = hash_table[index];
while(strcmp(temp->name,op)!=0 && temp!=NULL) //loop until
the opcode is not found or the temp pointer not pointing to NULL
{
temp = temp->next;
}
if(temp == NULL)
{
printf("Opcode not found!");
return NULL;
}
else
{
return temp;
}
}

}
char * getOpcodeFormat(Opcode* temp)
{
return temp->format;
}

int main()
{
FILE *input_opcode;
FILE *output_machine_code;
FILE *input_instructions;
int ilc=0; //Instruction Location Counter
int base = 0;
char c,c2,c3,temp;
char opcode[100];
char machine_code[100];
char format[5];

input_opcode = fopen("input_opcode.txt","r+"); //input_opcode


contains a list of opcodes followed by their format and mac.code
if (input_opcode == NULL)
printf("FILE OPENING PROBLEM");
char test1[50];
do
{
c = fscanf(input_opcode,"%s",opcode);//Assuming to get opcode
as a string in opcode array
c2= fscanf(input_opcode,"%s",machine_code);//Assuming to get
a the integer as a string in machine_code array
c3= fscanf(input_opcode,"%s",format);
//now we will create node of each string
struct Opcode* Node = (struct Opcode *)
malloc(sizeof(Opcode));

strcpy(Node->name,opcode);
//Name of the opcode is fed
strcpy(Node->code,machine_code);
//Machine code of the opcode is fed
strcpy(Node->format,format);
//Format of the opcode is fed
// printf("BEFORE INSERTING NAME:: %s ,CODE:: %s and
format",Node->name,Node->code,Node->format);
insertIntoHashMap(Node);

}while(fgets(test1, sizeof test1, input_opcode)!=NULL);

//At this point we have a hash-map of Opcodes

printf("Hash-map Created Successfully!\n");


/*TEST:: PRINTING HASHTABLE with hashcode*/
int i=0;
for(i=0;i<13;i++)
{

if(hash_table[i]!=NULL)
{

Opcode* temp = hash_table[i];

while(temp!=NULL)
{
printf("NAME:: %s and CODE:: %s and format:: %s
\n",temp->name,temp->code,temp->format);
temp = temp->next;
}

}
}
printf("Now reading Opcodes and Converting them to machine
codes\n");
input_instructions = fopen("input_instructions.txt","r+");
output_machine_code = fopen("output_machine_code.txt","w+");
char k;
char op[100];

/********************************************************************
***************************/
/*First pass for generation of symbol table*/

while ( fgets ( op, sizeof op, input_instructions ) != NULL ) /*


read a line */
{
int l=0;

while(op[l+1]!='\0')
{
if(op[l]==':') //Its a label
{
Symbol *t;
struct Symbol *temp = (struct Symbol*)
malloc(sizeof(Symbol)); //dynamic memory allocation for a node of
symbol
int i=0;
for(;i<l;i++)
temp->name[i] = op[i];
temp->name[i] = '\0';
temp->add = ilc + 1 + base;
temp->next = NULL;
if(head == NULL) //boundary condition for implementing
symbol table using linked list
head = temp;
else //adding new symbol node to existing table of nodes
{
t = head;
while(t->next!=NULL)
t= t->next;
t->next = temp;
}
//handle label
}
l++;
}
ilc++;
}
fclose(input_instructions);

/********************************************************************
***************************/
/*Second pass for generation of binary codes*/
input_instructions = fopen("input_instructions.txt","r+");
int * binary;
char test[100];
int count;

do
{
k=fscanf(input_instructions,"%s",op);
printf("WORD SCANNED IS %s \n",op);
/*check if opcode or label*/
int l=0;
while(op[l+1]!='\0')
{
l++;
}
if(op[l]==':') //Its a label
{
printf("Label Found!\n");
fprintf(output_machine_code,"\n");
//handle label
}
else
{
char temp[100];
char temp2[100];
char temp3[100];
int temp4;
//handle opcode and print corresponding machine code
Opcode* current_node = getOpcodeNode(op);
fprintf(output_machine_code,"%s",current_node-
>code);//print machine code of the opcode

if (strcmp("z",getOpcodeFormat(current_node))==0)
//ZERO OPERAND INSTRUCTION
{
fprintf(output_machine_code,"\n");//Do nothing
}
else if(strcmp("r",getOpcodeFormat(current_node))==0)
//ONE OPERAND REGISTER OPERAND INSTRUCTION
{
k = fscanf(input_instructions,"%s",temp); //read
corresponding register code

fprintf(output_machine_code,"%s",getRegisterCode(temp)); //write
corresponding register code in binary
fprintf(output_machine_code,"\n");
}
else if(strcmp("a",getOpcodeFormat(current_node))==0)
//ONE OPERAND ADDRESS OPERAND INSTRUCTION
{
k = fscanf(input_instructions,"%s",temp);
binary = getAddressCode(temp); //write corresponding
address in binary
for(count=0;count<10;count++)
{
fprintf(output_machine_code,"%d",binary[count]);
}
fprintf(output_machine_code,"\n");
}
else if(strcmp("rr",getOpcodeFormat(current_node))==0)
//TWO OPERAND REGISTER REGISTER OPERAND INSTRUCTION
{
//printf("inside two");
k = fscanf(input_instructions,"%s",temp);
k = fscanf(input_instructions,"%s",temp2);

fprintf(output_machine_code,"%s",getRegisterCode(temp));

fprintf(output_machine_code,"%s",getRegisterCode(temp2));
fprintf(output_machine_code,"\n");
}
else if(strcmp("ri",getOpcodeFormat(current_node))==0)
//TWO OPERAND REGISTER CONSTANT INSTRUCTION
{
k = fscanf(input_instructions,"%s",temp);
k = fscanf(input_instructions,"%d",&temp4);

fprintf(output_machine_code,"%s",getRegisterCode(temp));
//
fprintf(output_machine_code,"%s",getConstantCode(temp4));
binary = conBin(temp4);
for(count=0;count<10;count++)
{
fprintf(output_machine_code,"%d",binary[count]);
}
fprintf(output_machine_code,"\n");
}
else if(strcmp("rrr",getOpcodeFormat(current_node))==0)
//THREE OPERAND REGISTER-REGISTER-REGISTER INSTRUCTION
{
k = fscanf(input_instructions,"%s",temp);
k = fscanf(input_instructions,"%s",temp2);
k = fscanf(input_instructions,"%s",temp3);

fprintf(output_machine_code,"%s",getRegisterCode(temp));

fprintf(output_machine_code,"%s",getRegisterCode(temp2));

fprintf(output_machine_code,"%s",getRegisterCode(temp3));
fprintf(output_machine_code,"\n");
}
else if(strcmp("rri",getOpcodeFormat(current_node))==0)
//THREE OPERAND REGISTER-REGISTER-INTERMEDIATE INSTRUCTION
{
k = fscanf(input_instructions,"%s",temp);
k = fscanf(input_instructions,"%s",temp2);
k = fscanf(input_instructions,"%d",&temp4);

fprintf(output_machine_code,"%s",getRegisterCode(temp));

fprintf(output_machine_code,"%s",getRegisterCode(temp2));
binary = conBin(temp4);
for(count=0;count<10;count++)
{
fprintf(output_machine_code,"%d",binary[count]);
}
fprintf(output_machine_code,"\n");
}
}

}while(fgets(test, sizeof test, input_instructions)!=NULL);


printf("\n\nSymbol Table\n\n");
fclose(input_instructions);
fclose(output_machine_code);
fclose(input_opcode);

/*PRINT SYMBOL TABLE*/


Symbol *p;
p=head;
FILE *f = fopen("symbol_table.txt","w+");
while(p!=NULL)
{
printf("%s :: ",p->name);
fprintf(f,"%s :: ",p->name);
printf("%d\n",p->add);
fprintf(f,"%d\n",p->add);
p = p->next;
}
return 0;
}

OUTPUT:
CONCLUSION:

Thus we have successfully implemented 2 pass assembler.


EXPERIMENT NO: 4

TITLE: Design of a MACRO PASS-I

THEORY:

A general-purpose macro processor or general purpose preprocessor is a macro processor


that is not tied to or integrated with a particular language or piece of software.

A macro processor is a program that copies a stream of text from one place to another,
making a systematic set of replacements as it does so. Macro processors are often
embedded in other programs, such as assemblers and compilers. Sometimes they are
standalone programs that can be used to process any kind of text.

Macro processors have been used for language expansion (defining new language constructs
that can be expressed in terms of existing language components), for systematic text
replacements that require decision making, and for text reformatting (e.g. conditional
extraction of material from an HTML file).

ALGORITHM

1. Start.
2. Start the program execution.
3. Macro instructions are included in a separate file.
4. The instructions with ‘macro’,’mend’,’call’ on them should not be printed in the
output.
5. Print all other instructions such as start,load,store,add,sub etc with their values.
6. Stop the program execution.
7. End

SOURCE CODE:

#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<stdlib.h>
void main()
{ char n1,n,c1,i;
char fn[10][10],ilab[20],iopd[20],m[20][3],oper[20],opd[20];
FILE *fp1,*fp2,*p[5];
clrscr();
n=0;
fp1=fopen("z:\macin.txt","r");
while(!feof(fp1))
{
fscanf(fp1,"%s%s%s",ilab,iopd,oper);
if(strcmp(iopd,"macro")==0)
n++;
}
printf("no.of macros=%d\n",n);
n1=n;
printf("enter the text filename \n");
for(i=0;i<n;i++)
{s
canf("%s",fn[i]);
p[i]=fopen(fn[i],"w");
}
n=0;
rewind(fp1);
while(!feof(fp1))
{
fscanf(fp1,"%s%s%s",ilab,iopd,oper);
if(strcmp(iopd,"macro")==0)
{s
trcpy(m[n],oper);
fscanf(fp1,"%s%s%s",ilab,iopd,oper);
while(strcmp(iopd,"mend")!=0)
{
fprintf(p[n],"%s%s%s\n",ilab,iopd,oper);
fscanf(fp1,"%s%s%s",ilab,iopd,oper);
}
fclose(p[n]);
n++;
}}
for(i=0;i<n1;i++)
p[i]=fopen(fn[i],"r");
fp2=fopen("z:\outm.txt","w");
rewind(fp1);
fscanf(fp1,"%s%s%s",ilab,iopd,oper);
while(!feof(fp1))
{ if(strcmp(iopd,"call")==0)
{
for(i=0;i<n1;i++)
{ if(strcmp(m[i],oper)==0)
{
rewind(p[i]);
fscanf(p[i],"%s%s%s",ilab,iopd,oper);
while(!feof(p[i]))
{
fprintf(fp2,"%s%s%s",ilab,iopd,oper);
c1=1;
fscanf(p[i],"%s%s%s",ilab,iopd,oper);
}
break;
}}} if(c1!=1)
fprintf(fp2,"%s%s%s\n",ilab,iopd,oper);
c1=0;
fscanf(fp1,"%s%s%s",ilab,iopd,oper);
}
fprintf(fp2,"%s%s%s\n",ilab,iopd,oper);
}

OUTPUT:
CONCLUSION:

Thus we have successfully implemented Macro Pass 1


EXPERIMENT NO: 5

TITLE: Implement Job scheduling algorithms: FCFS, SJF

THEORY:

First Come First Serve is a scheduling algorithm used by the CPU to schedule jobs. It is a
Non-Preemptive Algorithm. Priority is given according to which they are requested by the
processor. Let’s understand the concept in the following order:

The process that requests the services of CPU first, get the CPU first. This is the philosophy
used by the first come first serve algorithm.

TERMS In First Come First Serve


• Completion time: Time when the execution is completed.
• Turn Around Time: The sum of the burst time and waiting time gives the turn-around
time
• Waiting time: The time the processes need to wait for it to get the CPU and start
execution is called waiting time.

Important Points
• It is non-preemptive
• Average waiting time is not optimal
• Cannot utilize resources in parallel

SOURCE CODE: (FCFS)

#include<stdio.h>
int main()

{
int n,bt[20],wt[20],tat[20],avwt=0,avtat=0,i,j;
printf("Enter total number of processes(maximum 20):");
scanf("%d",&n);

printf("\nEnter Process Burst Time\n");


for(i=0;i<n;i++)
{
printf("P[%d]:",i+1);
scanf("%d",&bt[i]);
}

wt[0]=0;

for(i=1;i<n;i++)
{
wt[i]=0;
for(j=0;j<i;j++)
wt[i]+=bt[j];
}

printf("\nProcess\t\tBurst Time\tWaiting Time\tTurnaround Time");

for(i=0;i<n;i++)
{
tat[i]=bt[i]+wt[i];
avwt+=wt[i];
avtat+=tat[i];
printf("\nP[%d]\t\t%d\t\t%d\t\t%d",i+1,bt[i],wt[i],tat[i]);
}

avwt/=i;
avtat/=i;
printf("\n\nAverage Waiting Time:%d",avwt);
printf("\nAverage Turnaround Time:%d",avtat);

return 0;
}

SOURCE CODE: (SJF)

#include<stdio.h>
int main()
{
int bt[20],p[20],wt[20],tat[20],i,j,n,total=0,pos,temp;
float avg_wt,avg_tat;
printf("Enter number of process:");
scanf("%d",&n);

printf("\nEnter Burst Time:\n");


for(i=0;i<n;i++)
{
printf("p%d:",i+1);
scanf("%d",&bt[i]);
p[i]=i+1;
}

//sorting of burst times


for(i=0;i<n;i++)
{
pos=i;
for(j=i+1;j<n;j++)
{
if(bt[j]<bt[pos])
pos=j;
}

temp=bt[i];
bt[i]=bt[pos];
bt[pos]=temp;

temp=p[i];
p[i]=p[pos];
p[pos]=temp;
}

wt[0]=0;

for(i=1;i<n;i++)
{
wt[i]=0;
for(j=0;j<i;j++)
wt[i]+=bt[j];

total+=wt[i];
}

avg_wt=(float)total/n;
total=0;

printf("\nProcess\t Burst Time \tWaiting Time\tTurnaround


Time");
for(i=0;i<n;i++)
{
tat[i]=bt[i]+wt[i];
total+=tat[i];
printf("\np%d\t\t %d\t\t
%d\t\t\t%d",p[i],bt[i],wt[i],tat[i]);
}

avg_tat=(float)total/n;
printf("\n\nAverage Waiting Time=%f",avg_wt);
printf("\nAverage Turnaround Time=%f\n",avg_tat);
}
OUTPUT: (FCFS)

OUTPUT: (SJF)

CONCLUSION:

Thus we have successfully implemented fcfs and sjf Job Scheduling Algorithm
EXPERIMENT NO: 6

TITLE: Implement Bankers Algorithm for deadlock detection and avoidance

THEORY:

The banker’s algorithm which is also known as avoidance algorithm is a deadlock detection
algorithm. It was developed by Edsger Dijkstra. It is designed to check the safe state
whenever a resource is requested. It takes analogy of bank, where customer request to
withdraw cash. Based on some data the cash is lent to the customer. The banker can’t give
more cash than what the customer has requested for, and the total available cash. As this
algorithm uses bank analogy so named as banker’s algorithm

The basic data structures used to implement this algorithm are given below.
Let n be the total number of processes and m be the total number of resource types in the
system.
Available: A vector of length m. It shows number of available resources of each type. If
Available[i] = k, then k instances of resource Ri are available.
Max: An n×m matrix that contain maximum demand of each process. If Max[i,j] = k, then
process Pi can request maximum k instances of resource type Rj.
Allocation: An n×m matrix that contain number of resources of each type currently allocated
to each process. If Allocation[i,j] = k, then Pi is currently allocated k instances of resource type
Rj.
Need: An n×m matrix that shows the remaining resource need of each process. If Need[i,j] =
k, then process Pi may need k more instances of resource type Rj to complete the task.

SOURCE CODE:

#include <stdio.h>

int current[5][5], maximum_claim[5][5], available[5];


int allocation[5] = {0, 0, 0, 0, 0};
int maxres[5], running[5], safe = 0;
int counter = 0, i, j, exec, resources, processes, k = 1;
int main()
{
printf("\nEnter number of processes: ");
scanf("%d", &processes);

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


{
running[i] = 1;
counter++;
}

printf("\nEnter number of resources: ");


scanf("%d", &resources);

printf("\nEnter Claim Vector:");


for (i = 0; i < resources; i++)
{
scanf("%d", &maxres[i]);
}

printf("\nEnter Allocated Resource Table:\n");


for (i = 0; i < processes; i++)
{
for(j = 0; j < resources; j++)
{
scanf("%d", &current[i][j]);
}
}

printf("\nEnter Maximum Claim Table:\n");


for (i = 0; i < processes; i++)
{
for(j = 0; j < resources; j++)
{
scanf("%d", &maximum_claim[i][j]);
}
}

printf("\nThe Claim Vector is: ");


for (i = 0; i < resources; i++)
{
printf("\t%d", maxres[i]);
}

printf("\nThe Allocated Resource Table:\n");


for (i = 0; i < processes; i++)
{
for (j = 0; j < resources; j++)
{
printf("\t%d", current[i][j]);
}
printf("\n");
}

printf("\nThe Maximum Claim Table:\n");


for (i = 0; i < processes; i++)
{
for (j = 0; j < resources; j++)
{
printf("\t%d", maximum_claim[i][j]);
}
printf("\n");
}

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


{
for (j = 0; j < resources; j++)
{
allocation[j] += current[i][j];
}
}

printf("\nAllocated resources:");
for (i = 0; i < resources; i++)
{
printf("\t%d", allocation[i]);
}

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


{
available[i] = maxres[i] - allocation[i];
}

printf("\nAvailable resources:");
for (i = 0; i < resources; i++)
{
printf("\t%d", available[i]);
}
printf("\n");

while (counter != 0)
{
safe = 0;
for (i = 0; i < processes; i++)
{
if (running[i])
{
exec = 1;
for (j = 0; j < resources; j++)
{
if (maximum_claim[i][j] - current[i][j] >
available[j])
{
exec = 0;
break;
}
}
if (exec)
{
printf("\nProcess%d is executing\n", i + 1);
running[i] = 0;
counter--;
safe = 1;

for (j = 0; j < resources; j++)


{
available[j] += current[i][j];
}
break;
}
}
}
if (!safe)
{
printf("\nThe processes are in unsafe state.\n");
break;
}
else
{
printf("\nThe process is in safe state");
printf("\nAvailable vector:");

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


{
printf("\t%d", available[i]);
}

printf("\n");
}
}
return 0;
}
OUTPUT:

CONCLUSION:

Thus, we have successfully implemented Bankers Algorithm


EXPERIMENT NO: 7

TITLE: Implementation of page replacement algorithm: FIFO

THEORY:

In an operating system that uses paging for memory management, a page replacement
algorithm is needed to decide which page needs to be replaced when new page comes in.

Page Fault – A page fault happens when a running program accesses a memory page that is
mapped into the virtual address space, but not loaded in physical memory.
Since actual physical memory is much smaller than virtual memory, page faults happen. In
case of page fault, Operating System might have to replace one of the existing pages with the
newly needed page. Different page replacement algorithms suggest different ways to decide
which page to replace. The target for all algorithms is to reduce the number of page faults.

ALGORITHM

1. Start the process

2. Declare the size with respect to page length

3. Check the need of replacement from the page to memory

4. Check the need of replacement from old page to new page in memory

5. Forma queue to hold all pages

6. Insert the page require memory into the queue

7. Check for bad replacement and page fault

8. Get the number of processes to be inserted

9. Display the values

10. Stop the process

SOURCE CODE:

#include<stdio.h>
int main()
{
int i,j,n,a[50],frame[10],no,k,avail,count=0;
printf("\n ENTER THE NUMBER OF PAGES:\n");
scanf("%d",&n);
printf("\n ENTER THE PAGE NUMBER :\n");
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
printf("\n ENTER THE NUMBER OF FRAMES :");
scanf("%d",&no);
for(i=0;i<no;i++)
frame[i]= -1;
j=0;
printf("\tref string\t page frames\n");
for(i=1;i<=n;i++)
{
printf("%d\t\t",a[i]);
avail=0;
for(k=0;k<no;k++)
if(frame[k]==a[i])
avail=1;
if (avail==0)
{
frame[j]=a[i];
j=(j+1)%no;
count++;
for(k=0;k<no;k++)

printf("%d\t",frame[k]);
}
printf("\n");
}
printf("Page Fault Is %d",count);
return 0;
}

OUTPUT:
CONCLUSION:

Thus, we have implemented page replacement algorithm using FIFO algorithm.


EXPERIMENT NO: 8.a

TITLE: Study of System calls to list files, directories

THEORY:

A system call is a mechanism that provides the interface between a process and the operating
system. It is a programmatic method in which a computer program requests a service from the
kernel of the OS.
System call offers the services of the operating system to the user programs via API
(Application Programming Interface). System calls are the only entry points for the kernel
system.

File Management System Calls


File management system calls handle file manipulation jobs like creating a file, reading, and
writing, etc.
Functions:
• Create a file
• Delete file
• Open and close file
• Read, write, and reposition
• Get and set file attributes

SOURCE CODE:

#include <sys/types.h>
#include<stdio.h>
#include <sys/stat.h>
#include<stdlib.h>
#include <dirent.h>

void listDir(char *dirName)

DIR* dir;

struct dirent *dirEntry;

struct stat inode;

char name[1000];

dir = opendir(dirName);

if (dir == 0) {
perror ("File opening error");

exit(1);

while ((dirEntry=readdir(dir)) != 0) {

sprintf(name,"%s/%s",dirName,dirEntry->d_name);

lstat (name, &inode);

// test the type of file

if (S_ISDIR(inode.st_mode))

printf("directory ");

else if (S_ISREG(inode.st_mode))

printf ("file ");

else

if (S_ISLNK(inode.st_mode))

printf ("lnk ");

else;

printf(" %s\n", dirEntry->d_name);

int main(int argc, char **argv)

if (argc != 2) {

printf ("Use: %s name_dir\n", argv[0]);

exit(0);

}
printf("\nThe content of the directory is:\n\n");

listDir(argv[1]);

OUTPUT:

CONCLUSION:

Thus, we have implemented System calls in c to list files, directories


EXPERIMENT NO: 8.b

TITLE: Study of System calls to handles process

THEORY:

A system call is a mechanism that provides the interface between a process and the operating
system. It is a programmatic method in which a computer program requests a service from the
kernel of the OS.
System call offers the services of the operating system to the user programs via API
(Application Programming Interface). System calls are the only entry points for the kernel
system.

Process Control System calls


This system calls perform the task of process creation, process termination, etc.
Functions:
• End and Abort
• Load and Execute
• Create Process and Terminate Process
• Wait and Signed Event
• Allocate and free memory

SOURCE CODE:

#include <unistd.h> /* Symbolic Constants */


#include <sys/types.h> /* Primitive System Data Types */
#include <errno.h> /* Errors */
#include <stdio.h> /* Input/Output */
#include <sys/wait.h> /* Wait for Process Termination */
#include <stdlib.h> /* General Utilities */

int main()
{
pid_t childpid; /* variable to store the child's pid */
int status; /* parent process: child's exit status */

/* only 1 int variable is needed because each process would have


its
own instance of the variable
here, 2 int variables are used for clarity */

/* now create new process */


childpid = fork();

if (childpid >= 0) /* fork succeeded */


{
if (childpid == 0) /* fork() returns 0 to the child process */
{
printf("CHILD: I am the child process!\n");
printf("CHILD: Here's my PID: %d\n", getpid());
printf("CHILD: My parent's PID is: %d\n", getppid());
printf("CHILD: Sleeping for 1 second...\n");
sleep(1);
printf("Child: Now, I woke up and am executing date
command \n\n");
execl("/bin/date", "date", 0, (char*)0);
perror("execl() failure!\n\n");

}
else /* fork() returns new pid to the parent process */
{
printf("PARENT: I am the parent process!\n");
printf("PARENT: Here's my PID: %d\n", getpid());
printf("PARENT: The value of my copy of childpid is
%d\n", childpid);
printf("PARENT: I will now wait for my child to
exit.\n");
wait(&status); /* wait for child to exit, and store
its status */
printf("PARENT: Child's exit code is: %d\n",
WEXITSTATUS(status));
printf("PARENT: Goodbye!\n");
exit(0); /* parent exits */
}
}
else /* fork returns -1 on failure */
{
perror("fork"); /* display error message */
exit(0);
}
}
OUTPUT:

CONCLUSION:

Thus, we have implemented System calls in c to handle processes

You might also like