fork() Experiments

Write the simple fork() program explained in the class where the parent and child simply print and exit. Then, do the following:
  1. Observe in what order the print statements come by running the program multiple times. Is it always in the same order or different? Is it different for different people?
  2. Put a sleep of 5 seconds in parent and child and check the PIDs using the ps command. Check that the PPID of the child is indeed the PID of the parent process.
  3. Remove the sleep in child while retaining it in parent. Using the ps command check the state of the child process.
  4. Remove the sleep in parent and not in child. Verify if the child dies or is inherited by init.
  5. Have two variables -- one global and one local to main(). Initialize them before fork(). Print the values in parent and child after fork(). What are the values?
  6. Modify the values of both the local and global variables in first, the parent and then the child. In each case, print the values in both the processes. What are the values?
  7. Open a file before fork(). After fork(), write to the file from parent and child the strings "From Parent" and "From Child" to the file. In what order are they written to the file? Are the strings overwritten or one after the other?
  8. Add "\n" to the strings of the previous experiment. Is there any difference in observed output?


exec() Experiments

  1. Write a program that simply calls execl() with some command without calling fork(). Have a variable for the return value of execl() and print it to stderr and then exit from your program. Observe if the printf() is executed in your program when a) command is a known and available command b) not a meaningful command.
  2. Write a program that calls fork() and then call execl() in a) Parent and b) in Child. Is there any difference?
  3. Open a file in your program using system call open() before fork(). Pass this file descriptor to execl() as an argument. Please remember that args are char*. So, you need to pass a string and not an integer. Are you able to use this fd and write to the file (you have to use the write system call) without opening it again after execl() in Child?


pipe() Experiments

  1. Use pipe() to create two pipes. Then, fork(). Close the read side of one pipe and write side of one pipe in both processes to create a bidirectional IPC. Use the pipe to send messages from one process to another and print them.
  2. When writing to pipes, have both processes first write to the pipe and then read from the other pipe.
  3. Have one process first write and then read whereas the other process first reads and then sends back the same message back to the other process. Read in the first process and print the message to the display.
  4. Have both processes first read from the pipe and then write to the pipe. What happens?
  5. Open only one pipe before fork(). After fork(), have a sleep in parent for say 2 seconds. In child, close both fds and go to sleep for 5 seconds. In parent, after sleep, write to the pipe. What happens?


FIFO Experiments

  1. Download the FIFO program. Put a sleep in the parent process and verify that the FIFO has a presence in the file system by checking if the files /tmp/fifo.1 and /tmp/fifo.2 exist.
  2. After the processes exit, verify if they still exist.
  3. Comment out the unlink() statements and verify if they still exist after the processes exit.
  4. Reboot the system and check if the files still exist without unlink. Check what happens if the names of the files are modified to your home directory on NFS? What happens if it is your home directory in your laptop?
  5. Are you able to remove these using "rm" command if they still exist after rebooting?


Multithreading Experiments

  1. Use the program demonstrated in the class where we pass the address of the variable i to the thread as a parameter. Print the value of this parameter from each thread created. What is the value printed? Why do you think it is so?
  2. Write a program in which you create 2 threads and pass 1,2 to the thread as a parameter. In the thread function, print the value of the parameter passed 10 times. Have a global variable initialised to 0. In the thread function, increment this counter and print the value of the tid and counter value 10 times. Check the counter value printed from the threads. Is there any inconsistency in the value or is the output as you expected? Experiment the same by adding a mutex around the critical section of incrementing the counter. Print the values and check if there is any difference in output. Is there inconsistency in values? What is needed if we want to ensure that the value of the counter must be printed in a certain order?
  3. File experiment: Write the counter value to the file strictly alternately from the two threads. How do you do this? Use two functions for the two threads. Use wait() in one and signal() in another.


Program for mimicking ps command

Write a program to read the /proc filesystem and print the following for all the processes listed there:

PID, PPID, STATE, COMMAND, No. of Files open

Since for all the root or privileged processes, you are not allowed to read the no. of files open, print NA for those. For all user processes, print the no. of files open.

Below are some Hints for the assignment.


Implementation of Banker's Algorithm

In this assignment, you need to implement the Banker's algorithm. The input to the program is the name of a file (given as command line argument) which will contain all the necessary information about the resource types, instances and maximum needs and current allocation of processes. Another file will contain the various requests which you need to check and determine if they will leave the system in a safe state or the process needs to be blocked for now. For each request, print whether it resulted in an unsafe state or a safe state. Make sure your output is meaningful instead of just printing "safe"/"unsafe".

The format of the first file is as follows:

-----------------------------------------------

#Number of resource types, Number of processes

M, N

# Total instances of each resource type

R1, R2, R3, ..., Rm

# Each line below gives the maximum requirement of a process

P1R1, P1R2, P1R3, ..., P1Rm

P1R1, P1R2, P1R3, ..., P1Rm

...

PnR1, PnR2, PnR3, ..., PnRm

# Each line below gives the current allocation to a process

P1R1, P1R2, P1R3, ..., P1Rm

P1R1, P1R2, P1R3, ..., P1Rm

...

PnR1, PnR2, PnR3, ..., PnRm

-----------------------------------------------

The format of the second file is as follows:

-----------------------------------------------

Pi: R1, R2, R3, ..., Rm

Pj: R1, R2, R3, ..., Rm

Pi: R1, R2, R3, ..., Rm

Pk: R1, R2, R3, ..., Rm

-----------------------------------------------

The Data file for the example in the book and the Two requests given for the same in the book can be downloaded for basic testing of your code. Please note that any line in the file that starts with a "#" in the first column is a comment and has to be ignored by the parser you write.


Memory Allocation Algorithms -- First, Best and Worst Fit

Contiguous Memory Allocation Algorithms

A file will be given as input (name taken as a command line parameter). The file consists of the following information:

# Total Memory of the system in KB

4096

# Total number of holes

5

# Hole information in the form of start offset, hole size in KB

500,100

1024,256

2048,1024

# Process memory reqts

600

200

50

100

1000

You need to read this information from the file and allocate the memory to the processes in the order in which they appear. For the example above, first you have to allocate 600KB, then 200KB and so on. Remember that you will have to update the hole information as you allocate. This gives the initial hole information only. You need to use the updated hole information for allocating to subsequent processes.

Output: The output should consist of starting address where the process is allocated, the amount of memory lost to external fragmentation for each of first fit, best fit and worst fit algorithms.

NOTE: If something is not clear, do NOT make assumptions. Get clarification on the specification BEFORE implementation.


Paging Algorithm

Assume a 32-bit processor. The permissions are given as "r,w,-" or "r,-,x" or "r,-,-". They represent RW, RX and R permissions on those pages. The operation in the format below is one of r, w, x. If the corresponding page has the permission, it is a valid operation; otherwise, it is not. Similarly, if the page no extracted from the virtualAddr is more than the last page for that process, it is an invalid operation.

The output of the program should be as follows:

PID virtualAddr operation pageno phyAddr

The operation is same as input if it is allowed; otherwise it should be "Invalid op". If the page no. is valid, print the page no; otherwise, NA. Finally, give the phyAddr for all valid cases.

The input file has the following format:

numProcesses pagesize

# PID

pageno frameBaseAddr perms

...

pageno frameBaseAddr perms

...

# PID

pageno frameBaseAddr perms

...

pageno frameBaseAddr perms

# VA

PID virtualAddr operation

PID virtualAddr operation

...

PID virtualAddr operation

An Example File may be downloaded to see the format of the file.