include file, and the include file contain the declaration of "fork" system call. When successful, "fork" returns the process ID of the child process in the parent process, and it returns a "0" in the child process."> include file, and the include file contain the declaration of "fork" system call. When successful, "fork" returns the process ID of the child process in the parent process, and it returns a "0" in the child process.">

Presentation is loading. Please wait.

Presentation is loading. Please wait.

Operating systems Lab 04 System Call, Nested Fork(),Exec(),Pipe()

Similar presentations


Presentation on theme: "Operating systems Lab 04 System Call, Nested Fork(),Exec(),Pipe()"— Presentation transcript:

1 Operating systems Lab 04 System Call, Nested Fork(),Exec(),Pipe()
Lab Instructor: Syed Aftab Rashid

2 Fork() System Call An existing process is termed the "parent" generates a new process called the "child ". The prototype of "fork" call is: pid_t fork(void); where the definition of "pid_t" is given in <sys/types> include file, and the include file <unistd.h> contain the declaration of "fork" system call. When successful, "fork" returns the process ID of the child process in the parent process, and it returns a "0" in the child process.

3 Fork() System Call By checking the return value from "fork", a process can easily determine if it is a parent or child process. A process can generate multiple child processes, but each child process has only one parent. What happens when a fork system call is made? When a fork system call is made, the operating system generates a copy of the parent process which becomes the child process. The OS will pass to the child process most of the parents system information (e.g. open file descriptors, environment information etc.)

4 Fork() System Call Some information, however, is unique to the child process. Process ID Different parent process ID Process times Own copy of file descriptors Resource utilization (initialized to zero)

5 Fork() pid_t new_pid; new_pid = fork(); switch(new_pid) { case -1 : /* Error */ break; case 0 : /* I am child */ default : /* I am parent */ }

6 Example of fork( ) int main(int argc, char *argv[]) {
char *name = argv[0]; int child_pid = fork(); if (child_pid == 0) cout<<“Child of <<name<<“sees PID of”<<child_pid; return 0; } else cout<<“I am the parent<<name<<“My child is”<<child_pid; } Output: % ./forktest Child of forktest sees PID of 0 I am the parent forktest. My child is 486

7 Example

8 Output

9 How can a parent and child process communicate?
Through any of the normal IPC mechanism schemes. But have special ways to communicate For example The variables are replicas The parent receives the exit status of the child

10 The wait() System Call A child program returns a value to the parent, so the parent must arrange to receive that value The wait() system call serves this purpose pid_t wait(int *status) it puts the parent to sleep waiting for a child’s result when a child calls exit(), the OS unblocks the parent and returns the value passed by exit() as a result of the wait call (along with the pid of the child) if there are no children alive, wait() returns immediately also, if there are zombies, wait() returns one of the values immediately (and deallocates the zombie)

11 Wait() #include <sys/types.h> #include <sys/wait.h>
The wait function suspends execution of the current process until a child has exited, or until a signal is delivered #include <sys/types.h> #include <sys/wait.h> pid_t wait(int *status); pid_t gets the PID from the Child

12 But we want the child process to do something else…
Fork creates an exact copy of the parent process The fork syscall returns a zero to the child and the child process ID to the parent int pid; int status = 0; if (pid = fork()) { /* parent */ …… pid = wait(&status); } else { /* child */ exit(status); } Parent uses wait to sleep until the child exits; wait returns child pid and status. Wait variants allow wait on a specific child, or notification of stops and other signals Child process passes status back to parent on exit, to report success/failure

13 Kill() #include <sys/types.h> #include <signal.h>
The kill() system call can be used to send any signal to any process group or process. If pid is positive, then signal sig is sent to pid. If pid equals 0, then sig is sent to every process in the process group of the current process. #include <sys/types.h> #include <signal.h> int kill(pid_t pid, int sig); On success, zero is returned. On error, -1 is returned, and errno is set appropriately

14 Read() On success, the number of bytes read is returned
read() attempts to read up to count bytes from file descriptor fd into the buffer starting at buf. If count is zero, read() returns zero and has no other results. If count is greater than SSIZE_MAX, the result is unspecified. #include <unistd.h> ssize_t read(int fd, void *buf, size_t count); On success, the number of bytes read is returned

15 Write() #include <unistd.h>
write writes up to count bytes to the file referenced by the file descriptor fd from the buffer starting at buf #include <unistd.h> ssize_t write(int fd, const void *buf, size_t count); On success, the number of bytes written are returned (zero indicates nothing was written). On error, -1 is returned

16 What is a zombie? In the interval between the child terminating and the parent calling wait(), the child is said to be a ‘zombie’. Even though its not running its taking up an entry in the process table. The process table has a limited number of entries.

17 What is a zombie? If the parent terminates without calling wait(), the child is adopted by init process. The solution is: Ensure that your parent process calls wait() or waitpid or etc, for every child process that terminates.

18 Exit() #include <stdlib.h>; int main() { exit(0); }
A computer process terminates its execution by making an exit system call #include <stdlib.h>; int main() { exit(0); }

19 exit() void exit(int status);
After the program finishes execution, it calls exit() This system call: takes the “result” of the program as an argument closes all open files, connections, etc. deallocates memory deallocates most of the OS structures supporting the process checks if parent is alive: If so, it holds the result value until parent requests it, process does not really die, but it enters the zombie/defunct state If not, it deallocates all data structures, the process is dead

20 Exercise Write a C++ program in which a parent process creates a child process using a fork() system call. The child takes a number as input and parent prints the input number.

21 Solution int main() {int variable; pid_t p=fork(); if(p==0) {
cout<<"hello this is child\n"; cout<<"enter value :"; cin>>variable; cout<<endl; exit(variable); } else {wait(&variable); cout<<"hello this is parent\n"; cout<<"value is :"<<(variable/256); return 0;

22 Nested Fork() OUTPUT The Sequence of output can vary to certain extent depending on CPU Scheduler.

23 Nested Fork() Try This Int main() { printf("L0\n"); if (fork() != 0)
} printf("Bye\n");

24 Nested Fork() Quiz-4 int main() { int pid, i; for (i=2;i>=0;i--)
pid = fork(); cout<<pid<<"\n"; } exit(0);

25 Exec() System Call The “exec” function is actually a family of six functions each with slightly different calling conventions and use. Like “fork”, “exec” is declared in <unistd.h>. “exec” completely replaces the calling process’s image with that of the program being executed. “fork” creates a new process, and so generates a new PID. “exec” initiates a new program, replacing the original process. Therefore, the PID of an “execed” process doesn’t change. If successful, the “exec” calls do not return as the calling image is lost.

26 Exec() System Call The prototypes are:
int execl (const char *path, const char *arg, …); int execlp(const char *file, const char *arg, …); int execle(const char *path, const char *arg, char *const envp[]); int execv(const char *path, char *const argv[]); int execve(const char*path, const char *argv[], char *const envp[]); int execvp(const char *file, char *const argv[]);

27 Exec() in Detail The naming convention for the “exec” system calls reflects their functionality. The next letter in the call name indicates if the call takes its arguments in a “list format” (i.e. literally specified as a series of arguments) or as a pointer to an “array of arguments”. The presence of an “l” indicates a “list arrangement” and “v” the “vector or array arrangement”. The three of the functions (execl, execle, execlp) thus expect a comma separated list of arguments, terminated by a NULL pointer.

28 The next letter of the call name, if present, is either a “e” or “p”.
The presence of a “p” indicates the current PATH string should be used when the system searches for executable files. (If the executable file is script file, the shell is invoked to execute the script. The shell is then passed the specified argument information). Each string in this array takes the form of a “name = value” pair, where “name” is the name of an environment variable and “value” is its value. The other four functions inherit the environment implicitly through a global variable named “environ” that points to an array of strings containing the calling process environment. To manipulate the environment, we use “getenv” and “putenv” functions declared in <stdlib.h>.

29 Example Executing the “ls –a” command using Exec()
#include<iostream> Using namespace std; #include <unistd.h> #include <stdio.h> int main() { printf(“Running ls with execlp\n”); execlp(“ls”, “ls”, “-a”, 0); printf(“Done.\n”); exit(0); }

30 Example Create or Edit an existing file using Execvp()

31 Using execlp()

32 Exercise Write a program that use fork() to create a child process the child then uses exec() to remove a file entered by the user while the parents waits for the child to terminate and call exit() after child termination.

33 File Descriptors Every time a file is opened, one of the free file pointers in the files_struct is used to point to the new file structure. Linux processes expect three file descriptors to be open when they start. These are known as standard input(0), standard output(1) and standard error(2). The program treat them all as files. These three are usually inherited from the creating parent process. All accesses to files are via standard system calls which pass or return file descriptors.

34 File Descriptors char buffer[10];
Read from standard input (by default it is keyboard) read(0,buffer,5); Write to standard output (by default it is monitor)) write(1,buffer,5); By changing the file descriptors we can write to files

35 Pipes A pipe is implemented using two file data structures which both point at the same temporary data node. This hides the underlying differences from the generic system calls which read and write to ordinary files. Thus, reading/writing to a pipe is similar to reading/writing to a file Pipe write() read() Pfd[1] Pfd[0]

36 Pipe Creation #include <unistd.h> int pipe(int filedes[2]);
Creates a pair of file descriptors pointing to a pipe inode Places them in the array pointed to by filedes filedes[0] is for reading filedes[1] is for writing. On success, zero is returned. On error, -1 is returned

37 Pipe Creation int main() { int pfds[2]; if (pipe(pfds) == -1) { perror("pipe"); exit(1); } }

38 Reading/Writing from/to a Pipe
int read(int filedescriptor, char *buffer, int bytetoread); int write(int filedescriptor,char *buffer,int bytetowrite);

39 Example int main() { int pfds[2]; char buf[30];
if (pipe(pfds) == -1) { perror("pipe"); exit(1); } printf("writing to file descriptor #%d\n", pfds[1]); write(pfds[1], "test", 5); printf("reading from file descriptor #%d\n",pfds[0]); read(pfds[0], buf, 5); printf("read %s\n", buf); }

40 InterProcess Communication using Pipes
Remember: the two processes have a parent / child relationship The child was created by a fork() call that was executed by the parent. The child process is an image of the parent process Thus, all the file descriptors that are opened by the parent are now available in the child

41 InterProcess Communication using Pipes
The file descriptors refer to the same I/O entity, in this case a pipe. The pipe is inherited by the child pfds[1] pfds[0] Parent pfds[1] pfds[0] Child 2. Fork() flow of data Pipe Process Kernel 1. Pipe()

42 Exercise Write a program that creates a child process using fork().The child sends a message using Pipe() to the parent the parent receives and display the message. Hint: To allow one way communication each process should close one end of the pipe. The file descriptors associated with a pipe can be closed with the close(fd) system call

43 Solution

44 Example Implementing “ls |sort” using Pipe()

45 Exercise Write down a program using pipes to implement the following Linux command. ls | wc [Hint: Create child process and perform communication between parent and child using previous example]

46 Thank You


Download ppt "Operating systems Lab 04 System Call, Nested Fork(),Exec(),Pipe()"

Similar presentations


Ads by Google