Program Assignment : Process Management
Objective: This program assignment is given to the Operating Systems course to allow the students to figure out how a single process (parent process) creates a child process and how they work on Unix/Linux(/Mac OS X/Windows) environment. Additionally, student should combine the code for describing inter-process communication into this assignment. Both parent and child processes interact with each other through shared memory-based communication scheme or message passing scheme.
Environment: Unix/Linux environment (VM Linux or Triton Server, or Mac OS X), Windows platform
Language: C or C++, Java
Requirements:
i. You have wide range of choices for this assignment. First, design your program to explain the basic concept of the process management in Unix Kernel. This main idea will be evolved to show your understanding on inter-process communication, file processing, etc.
ii. Refer to the following system calls:
- fork(), getpid(), family of exec(), wait(), sleep() system calls for process management
- shmget(), shmat(), shmdt(), shmctl() for shared memory support or
- msgget(), msgsnd(), msgrcv(), msgctl(), etc. for message passing support
iii. The program should present that two different processes, both parent and child, execute as they are supposed to.
iv. The output should contain the screen capture of the execution procedure of the program.
v. Interaction between parent and child processes can be provided through inter-process communication schemes, such as shared-memory or message passing schemes.
vi. Result should be organized as a document which explains the overview of your program, code, execution results, and the conclusion including justification of your program, lessons you've learned, comments, etc.
Note:
i. In addition, please try to understand how the local and global variables work across the processes
ii. read() or write () functions are used to understand how they work on the different processes.
iii. For extra credit, you can also incorporate advanced features, like socket or thread functions, into your code.
Examples:
1. Process Creation and IPC with Shared Memory Scheme
=============================================================
#include <stdio.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main(){
pid_t pid;
int segment_id; //allocate the memory
char *shared_memory; //pointer to memory
const int size = 4096;
segment_id = shmget(IPC_PRIVATE, size, S_IRUSR | S_IWUSR);
shared_memory = (char *) shmat(segment_id, NULL, 0);
pid = fork();
if(pid < 0) { //error
fprintf(stderr, "Fork failed");
return 1;
}
else if(pid == 0){ //child process
char *child_shared_memory;
child_shared_memory = (char *) shmat(segment_id,NULL,0); //attach mem
sprintf(child_shared_memory, "Hello parent process!"); //write to the shared mem
shmdt(child_shared_memory);
}
else ...
Program Assignment Process ManagementObjective This program a.docx
1. Program Assignment : Process Management
Objective: This program assignment is given to the Operating
Systems course to allow the students to figure out how a single
process (parent process) creates a child process and how they
work on Unix/Linux(/Mac OS X/Windows) environment.
Additionally, student should combine the code for describing
inter-process communication into this assignment. Both parent
and child processes interact with each other through shared
memory-based communication scheme or message passing
scheme.
Environment: Unix/Linux environment (VM Linux or Triton
Server, or Mac OS X), Windows platform
Language: C or C++, Java
Requirements:
i. You have wide range of choices for this assignment. First,
design your program to explain the basic concept of the process
management in Unix Kernel. This main idea will be evolved to
show your understanding on inter-process communication, file
processing, etc.
ii. Refer to the following system calls:
- fork(), getpid(), family of exec(), wait(), sleep() system calls
for process management
- shmget(), shmat(), shmdt(), shmctl() for shared memory
support or
- msgget(), msgsnd(), msgrcv(), msgctl(), etc. for message
passing support
iii. The program should present that two different processes,
both parent and child, execute as they are supposed to.
iv. The output should contain the screen capture of the
execution procedure of the program.
v. Interaction between parent and child processes can be
provided through inter-process communication schemes, such as
shared-memory or message passing schemes.
vi. Result should be organized as a document which explains the
2. overview of your program, code, execution results, and the
conclusion including justification of your program, lessons
you've learned, comments, etc.
Note:
i. In addition, please try to understand how the local and global
variables work across the processes
ii. read() or write () functions are used to understand how they
work on the different processes.
iii. For extra credit, you can also incorporate advanced features,
like socket or thread functions, into your code.
Examples:
1. Process Creation and IPC with Shared Memory Scheme
===============================================
==============
#include <stdio.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main(){
pid_t pid;
int segment_id; //allocate the memory
char *shared_memory; //pointer to memory
const int size = 4096;
segment_id = shmget(IPC_PRIVATE, size, S_IRUSR |
S_IWUSR);
shared_memory = (char *) shmat(segment_id, NULL, 0);
pid = fork();
if(pid < 0) { //error
fprintf(stderr, "Fork failed");
return 1;
}
else if(pid == 0){ //child process
char *child_shared_memory;
child_shared_memory = (char *)
3. shmat(segment_id,NULL,0); //attach mem
sprintf(child_shared_memory, "Hello parent
process!"); //write to the shared mem
shmdt(child_shared_memory);
}
else {//parent process
wait(NULL);
printf("Child process completed.n");
printf("The child process has written to the shared memory.nIt
has said: %sn", shared_memory); //read from shared mem
shmdt(shared_memory);
shmctl(segment_id, IPC_RMID, NULL);
}
return 0;
}
===============================================
==============
2. Process Creation and IPC with Message Passing Scheme
===============================================
==============
#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#define N 20
typedef struct{
long stype;
char input[N];
}msgq;
int origin = 12345;
int main(int argv, char * argc[]){
msgq sendq;
4. msgq rcvq;
size_t qlen;
key_t key=1111;
pid_t pid_p, pid_c;
int msgid = msgget((key_t)1111, 0666|
IPC_CREAT); //declare the msg queue id
int shrm_id, shrm_size = 1024; //size of
memory for sharing
char * shrm_addr;
shrm_id = shmget(IPC_PRIVATE, shrm_size, S_IRUSR |
S_IWUSR); // get the id of memory for sharing
shrm_addr = (char*)shmat(shrm_id, NULL, 0);
pid_p = getpid(); // store parent_process_id into
variable ; pid_p
pid_c = fork(); // store child_process_id into
variable ; pid_c
//meaning of return value of fork()
//value < 0 : fork is failed
//value == 0 : child process
//value > 0 : parent process
if(pid_c < 0){
fprintf(stderr, "failed to fork()n"); // print error msg
by using stderr of fprintf
return 0;
}else if(pid_c ==0){
printf("start of child processn");
printf("--------------------------------nn");
printf("origin : %dn", origin);
origin++;
printf("value of origin after origin++; : %dnn",
origin);
5. char * c_shrm_addr = (char *)shmat(shrm_id, NULL,
0); // give shared memory to child by using shmat()
// NULL means find somewhere which has been
mapped
if(c_shrm_addr ==(void *) -1) // shmat() return (void
*)-1 when the sharing is failed
fprintf(stderr, "failed to sharen");
pid_c = getpid();
sendq.stype=1;
printf("input string that will be sent to parent process :
");
scanf("%s",sendq.input); //store the string for send to
parent into msg queue
qlen= strlen(sendq.input)+1;
if(msgsnd(msgid,&sendq, qlen ,IPC_NOWAIT)<0){
perror("msgsnd");
exit(0);
}
else{
printf("Msgsend : %sn", sendq.input);
}
printf("n--------------------------------n");
printf("end of child process n");
} else {
//now in parent process
printf("nstart of parent processn");
printf("--------------------------------nn");
6. char str[N];
int i = 0;
wait(NULL); //wait until the child process
finished
printf("n--------------------------------n");
printf("back to the parent process n");
printf("--------------------------------nn");
printf("origin : %dn", origin);
if(origin == 12345)
printf("changed origin value in child is not
applied to parentnn");
if(origin == 12346)
printf("changed origin value in child is applied ro
parentnn");
if((msgid = msgget(key,0666))<0){ //in case of
error in msgget
perror("msgget");
exit(1);
}
if(msgrcv(msgid,&rcvq,N+1,1,0)==0){ //in case of
error in msgrcv
perror("msgrcv");
exit(1);
}
printf("recieve : %snn",rcvq.input);
printf("child process refers to the memory of parent :
%xn", (int)shrm_addr);
pid_p = getpid(IPC_PRIVATE, IPC_CREAT);
printf("ID of Parent : %dn", pid_p);
7. printf("ID of Child : %dn", pid_c);
printf("n--------------------------------n");
printf("end of parent processnn");
}
shmdt(shrm_addr);
shmctl(shrm_id, IPC_RMID, NULL);
return 0;
}
===============================================
============== 3. Compiling and executing C codes
$ cc msgpass.c -o msgpass
$ ./msgpass
http://linux.die.net/man/3/exec
fork() creates a new process by duplicating the calling process.
The new process, referred to as the child, is an exact duplicate
of the calling process, referred to as the parent#include
<unistd.h>pid_t fork(void);
The exec() family of functions replaces the current process
image with a new process image. The functions described in this
manual page are front-ends for execve(2). (See the manual page
for execve(2) for further details about the replacement of the
current process image.)
The exec() family of functions include execl, execlp, execle,
execv, execvp, and execvpe to execute a file.
The ANSI prototype for execl() is:
8. int execl(const char *path, const char *arg0,..., const char
*argn, 0)
http://www.cems.uwe.ac.uk/~irjohnso/coursenotes/lrc/system/pc
/pc4.htm #inciude <stdio.h> #inciude <unistd.h> main()
{ execl("/bin/ls", "ls", "-l", 0); printf("Can
only get here on errorn"); }
The first parameter to execl() in this example is the full
pathname to the ls command. This is the file whose contents
will be run, provided the process has execute permission on the
file. The rest of the execl() parameters provide the strings to
which the argv array elements in the new program will point. In
this example, it means that the ls program will see the
string ls pointed to by its argv[0], and the string -l pointed to by
itsargv[1]. In addition to making all these parameters available
to the new program, the exec() calls also pass a value for the
variable: extern char **environ;
This variable has the same format as the argv variable except
that the items passed via environ are the values in the
environment of the process (like any exported shell variables),
rather than the command line parameters. In the case of execl(),
the value of the environ variable in the new program will be a
copy of the value of this variable in the calling process.
The execl() version of exec() is fine in the circumstances where
you can ex-plicitly list all of the parameters, as in the previous
example. Now suppose you want to write a program that doesn't
just run ls, but will run any program you wish, and pass it any
number of appropriate command line parameters.
Obviously, execl() won't do the job.
The example program below, which implements this
requirement, shows, however, that the system call execv() will
perform as required: #inciude <stdio.h> main(int argc, char
**argv) { if (argc==1) {
printf("Usage: run <command> [<paraneters>]n");
exit(1) } execv(argv[l], &argv[1));
9. printf("Sorry... couldn't run that!n"); }
The prototype for execv() shows that it only takes two
parameters, the first is the full pathname to the command to
execute and the second is the argv value you want to pass into
the new program. In the previous example this value was
derived from the argv value passed into the run command, so
that the run command can take the command line parameter
values you pass it and just pass them on. int execl(pathname,
argo, ..., argn, 0); int execv(pathname, argv); int
execlp(cmdname, arg0, ..., argn, 0); int execvp(cmdname,
argv); int execle(patbname, arg0, ..., arga, 0, envp); int
execve(pathname, argv, envp); char *pathname, *cmdname;
char *arg0, ..., *argn; char **argv, **envp;
pipe() creates a pipe, a unidirectional data channel that can be
used for interprocess communication. The array pipefd is used
to return two file descriptors referring to the ends of the
pipe. pipefd[0] refers to the read end of the
pipe. pipefd[1] refers to the write end of the pipe. Data written
to the write end of the pipe is buffered by the kernel until it is
read from the read end of the pipe#include <unistd.h>int
pipe(int pipefd[2]);#define _GNU_SOURCE /* See
feature_test_macros(7) */#include<fcntl.h> /* Obtain
O_* constant definitions */#include <unistd.h>int pipe2(int
pipefd[2], int flags);
read() attempts to read up to count bytes from file
descriptor fd into the buffer starting at buf.#include
<unistd.h>ssize_t read(int fd, void *buf, size_t count);
write() writes up to count bytes from the buffer pointed buf to
the file referred to by the file descriptor fd.#include
10. <unistd.h>ssize_t write(int fd, const void *buf, size_t count);
close() closes a file descriptor, so that it no longer refers to any
file and may be reused. Any record locks (see fcntl(2)) held on
the file it was associated with, and owned by the process, are
removed (regardless of the file descriptor that was used to
obtain the lock).
If fd is the last file descriptor referring to the underlying open
file description (seeopen(2)), the resources associated with the
open file description are freed; if the descriptor was the last
reference to a file which has been removed using unlink(2) the
file is deleted.#include <unistd.h>int close(int fd);
Sample Program 1
/****************************************************
************ * * Example: to demonstrate fork() and execl()
and system calls *
*****************************************************
**********/#include <stdio.h>#include <stdlib.h>#include
<sys/types.h>#include <unistd.h>#include <sys/wait.h>int
main( int argc, char *argv[], char *env[] ){ pid_t my_pid,
parent_pid, child_pid; int status;/* get and print my pid and
my parent's pid. */ my_pid = getpid(); parent_pid =
getppid(); printf("n Parent: my pid is %dnn", my_pid);
printf("Parent: my parent's pid is %dnn", parent_pid);/* print
error message if fork() fails */ if((child_pid = fork()) < 0 ) {
perror("fork failure"); exit(1); }/* fork() == 0 for child
process */ if(child_pid == 0) { printf("nChild: I am a new-
born process!nn"); my_pid = getpid(); parent_pid =
getppid(); printf("Child: my pid is: %dnn", my_pid);
printf("Child: my parent's pid is: %dnn", parent_pid);
printf("Child: I will sleep 3 seconds and then execute - date -
command nn"); sleep(3); printf("Child: Now, I woke up
and am executing date command nn"); execl("/bin/date",
"date", 0, 0); perror("execl() failure!nn"); printf("This
print is after execl() and should not have been executed if execl
11. were successful! nn"); _exit(1); }/* * parent process */
else { printf("nParent: I created a child process.nn");
printf("Parent: my child's pid is: %dnn", child_pid);
system("ps -acefl | grep ercal"); printf("n n");
wait(&status); /* can use wait(NULL) since exit status
from child is not used. */ printf("n Parent: my child is dead.
I am going to leave.n n "); } return 0;}
Sample Program 2
Execution > gcc –o proc proc.c> gcc –o fibo fibo.c> gcc –o pipe
pipe.c> ./proc
proc.c#include <stdio.h>#include <sys/shm.h>#include
<sys/stat.h>#include <sys/types.h>#include <unistd.h>int
main(){ pid_t pid; int segment_id; //allocate the memory
char *shared_memory; //pointer to memory const int size =
4096; segment_id = shmget(IPC_PRIVATE, size, S_IRUSR |
S_IWUSR); shared_memory = (char *) shmat(segment_id,
NULL, 0); pid = fork(); if(pid < 0) { //error
fprintf(stderr, "Fork failed"); return 1; } else if(pid
== 0){ //child process char *child_shared_memory;
child_shared_memory = (char *) shmat(segment_id,NULL,0);
//attach mem sprintf(child_shared_memory, "Hello
parent process!"); //write to
the shared mem shmdt(child_shared_memory);
execl("./pipe", "pipe", "3", 0); /* to call pipe program */
execl("./fibo", "fibo", "12", 0); /* to call fibo program */ }
else {//parent process wait(NULL);
printf("Child process completed.n"); printf("The
child process has written to the shared memory.n It
has said: %sn", shared_memory); //read from shared mem
shmdt(shared_memory); shmctl(segment_id,
IPC_RMID, NULL); } return 0;}
12. fibo.c#include <stdio.h>#include <stdlib.h>#include
<sys/types.h>#include <unistd.h>#include <string.h>int fibo(int
num);int main(int argc, char *argv[]) { if (argc != 2) {
fprintf(stderr, "argc %d n", argc); fprintf(stderr, "argv[0]:
%s >n", argv[0]); fprintf(stderr, "argv[1]: %s >n",
argv[1]); fprintf(stderr, "Usage: %s <string>n", argv[0]);
exit(EXIT_FAILURE); } int num = atoi(argv[1]); printf(
"%d'th Fibonacci number is %dn", num, fibo(num));
exit(EXIT_SUCCESS);} /* end of main */ int fibo(int num) {
if (num > 0) { if (num <=2) { return 1; } else {
return fibo(num-1) + fibo(num-2); } } else { return -1;
}} /* end of fibo() */
pipe.c#include <stdio.h>#include <stdlib.h>#include
<sys/shm.h>#include <sys/stat.h>#include <sys/wait.h>#include
<sys/types.h>#include <unistd.h>#include <string.h>int
segmentId;char *sharedMemory;int main(int argc, char *argv[])
{ int pipefd[2]; pid_t cpid; char buf; if (argc != 2) {
fprintf(stderr, "argc %d n", argc); fprintf(stderr, "argv[0]:
%s >n", argv[0]); fprintf(stderr, "argv[1]: %s >n",
argv[1]); fprintf(stderr, "Usage: %s <string>n", argv[0]);
exit(EXIT_FAILURE); } if (pipe(pipefd) == -1) {
perror("pipe"); exit(EXIT_FAILURE); } cpid = fork(); if
(cpid == -1) { perror("fork"); exit(EXIT_FAILURE); }
if (cpid == 0) { /* Child reads from pipe */ close(pipefd[1]);
/* Close unused write end */ while (read(pipefd[0], &buf, 1)
> 0) write(STDOUT_FILENO, &buf, 1);
write(STDOUT_FILENO, "n", 1); _exit(EXIT_SUCCESS);
} else { /* Parent writes argv[1] to pipe */
close(pipefd[0]); /* Close unsed read end */ write(pipefd[1],
argv[1], strlen(argv[1])); close(pipefd[1]); /* Reader will
see EOF */ wait (NULL); /* Wait for child */
exit(EXIT_SUCCESS); }}