Operating Systems 2017F Lecture 3: Difference between revisions
(4 intermediate revisions by the same user not shown) | |||
Line 17: | Line 17: | ||
- More on creating a process using fork(). | - More on creating a process using fork(). | ||
<syntaxhighlight lang="c"> | |||
#include <stdio.h> | #include <stdio.h> | ||
#include <unistd.h> | #include <unistd.h> | ||
Line 47: | Line 47: | ||
return 42; | return 42; | ||
} | } | ||
</syntaxhighlight> | |||
- sleep(int) | - sleep(int) | ||
- causes the current process to do nothing for the specified number of seconds. | - causes the current process to do nothing for the specified number of seconds. | ||
Line 68: | Line 68: | ||
- '''What happens in the conditional?''' | - '''What happens in the conditional?''' | ||
- When the parent process calls fork(), a child process is created and begins executing at the fork() statement. The OS returns a value from fork() which indicates which process | - When the parent process calls fork(), a child process is created and begins executing at the fork() statement. The OS returns a value from fork() which indicates which process | ||
currently running. | is currently running. | ||
- If fork() returns zero then the child sleeps for 3 seconds before printing. The sleep system call forces the child process to do nothing for 3 seconds. | - If fork() returns zero then the child sleeps for 3 seconds before printing. The sleep system call forces the child process to do nothing for 3 seconds. | ||
- if fork() returns anything else, it is assumed to be the parent process. In this case the wait() system call is run by the parent which causes the parent process to wait for its | - if fork() returns anything else, it is assumed to be the parent process. In this case the wait() system call is run by the parent which causes the parent process to wait for its | ||
to finish; then the printf executes and prints the child process id and its return value from main. The macro WEXITSTATUS retrieves 42. | child to finish; then the printf executes and prints the child process id and its return value from main. The macro WEXITSTATUS retrieves 42. | ||
==== What Happen to the child process after the parent process died? ==== | ==== What Happen to the child process after the parent process died? ==== | ||
Line 78: | Line 78: | ||
* In the demo showed in class, “system d user” became its new parent | * In the demo showed in class, “system d user” became its new parent | ||
**Use command "Pstree" to show process hierarchy | **Use command "Pstree" to show process hierarchy | ||
* Every process must have a valid process parent. Use "pstree" to see the tree structure | |||
* When a parent dies before a child "init" will adopt every orphan on the system | |||
==== What is zombie process? ==== | ==== What is zombie process? ==== | ||
Line 89: | Line 91: | ||
==== Manipulating environment variables==== | ==== Manipulating environment variables==== | ||
*argc tells the number of argument in command line, while argv[] contains the actual command obtained in the command line | *argc tells the number of argument in command line, while argv[] contains the actual command obtained in the command line | ||
=== Adding the execve() system call to the mix === | |||
<syntaxhighlight lang="c"> | |||
#include <stdio.h> | |||
#include <unistd.h> | |||
#include <sys/types.h> | |||
#include <sys/wait.h> | |||
int main(int argc, char* argv[], char* envp[]) { | |||
int child; | |||
int status; | |||
pid_t retval; | |||
int i; | |||
printf("You called me with %d arguments.\n", argc); | |||
for (i=0; i<argc; i++) { | |||
printf("Arg %d: %s\n", i, argv[i]); | |||
} | |||
child = fork(); | |||
printf("Hello! I am %d, my parent is %d.\n", | |||
getpid(), getppid()); | |||
if (child == 0) { | |||
/* We're the child */ | |||
execve("/bin/ls", argv, envp); | |||
sleep(3); | |||
printf("Child all done!\n"); | |||
} else { | |||
/* We're the parent */ | |||
retval = wait(&status); | |||
printf("Parent all done! Child %d returned %d.\n", | |||
(int) retval, WEXITSTATUS(status)); | |||
} | |||
return 42; | |||
} | |||
</syntaxhighlight> | |||
- int execve(const char *filename, char *const argv[], char *const envp[]) | |||
- this system call executes the program pointed to by filename | |||
- The child process becomes independent from its parent -- a new program | |||
- argv[] is an array of strings passed to the new program. The values are loaded into the array by execve not the kernel. | |||
- envp[] is an array of strings of the form key=value which are passed as environment to the new program | |||
- What happens when the if statement executes | |||
- execve creates a new program -- an independent process and passes arguments to the "ls" program. | |||
- execve stops the new process after it has completed. | |||
- Some interesting points about main(int argc, char* argv[], char* envp[]) | |||
- Notice that the size of the arrays are not defined. We have to use argc to get this information. Not good programming practice but is | |||
accepted because it is grandfathered from the early days of the c language. | |||
- arg[0] is always the name of the program. |
Latest revision as of 00:47, 5 October 2017
Video
Video from the lecture given on September 14, 2017 is now available.
Code
Code and files from the lecture (captured as they were at the end) are available here.
Notes
Commands
- -wall: show all warning
- less: allow screen navigation, hit q to quit
What is fork?
- Fork creates a new program but contains the same code (call the clone system call) and only argv[] and envp[] passed on to the new born program
- More on creating a process using fork().
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char* argv[], char* envp[]) {
int child;
int status;
pid_t retval;
child = fork();
printf("Hello! I am %d, my parent is %d.\n",
getpid(), getppid());
if (child == 0) {
/* We're the child */
sleep(3);
printf("Child all done!\n");
} else {
/* We're the parent */
retval = wait(&status);
printf("Parent all done! Child %d returned %d.\n",
(int) retval, WEXITSTATUS(status));
}
return 42;
}
- sleep(int) - causes the current process to do nothing for the specified number of seconds.
- pid_t = fork(void) - fork creates a clone of the parent process - pid is 0 when the child process is running and >0 when the parent process is running. Both processes will return from the system call to fork().
- pid_t = wait(int * status) - this system call is equivalent to pid_t = waitpid(-1, &status, 0) - the wait system call suspends the current process until one of its children has terminated. - pid_t specifies which child to wait for. Various options are available that define how to wait. - int* status holds the status of the wait system call. There are various macros that define what the status can be.
- What happens when the newline character is removed from the printf statement? - printf holds the output in a buffer until it receives a newline character. The result is the output does not print when expected. - The kernel is doing things as it is told, so the c library is at fault. - We could get the expected output if we bypass the c library using a system call: "write" - running an "strace" on the executable will show us the order in which the processes were run to help debug the problem.
- What happens in the conditional? - When the parent process calls fork(), a child process is created and begins executing at the fork() statement. The OS returns a value from fork() which indicates which process is currently running. - If fork() returns zero then the child sleeps for 3 seconds before printing. The sleep system call forces the child process to do nothing for 3 seconds. - if fork() returns anything else, it is assumed to be the parent process. In this case the wait() system call is run by the parent which causes the parent process to wait for its child to finish; then the printf executes and prints the child process id and its return value from main. The macro WEXITSTATUS retrieves 42.
What Happen to the child process after the parent process died?
- Every child process must have a currently running parent. When the parent process die, kernel collect the dead body(return value) and re-parent the process
- In the demo showed in class, “system d user” became its new parent
- Use command "Pstree" to show process hierarchy
- Every process must have a valid process parent. Use "pstree" to see the tree structure
- When a parent dies before a child "init" will adopt every orphan on the system
What is zombie process?
- When a process die it become 'zombie' (s = sleep, z = zombie)
- We can use wait to be a 'good' parent
How to load a new binary manually
- Use the execve command.
- We can fork child process to handle dangerous task (“Suicide Squad”), or handle all incoming request
Manipulating environment variables
- argc tells the number of argument in command line, while argv[] contains the actual command obtained in the command line
Adding the execve() system call to the mix
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char* argv[], char* envp[]) {
int child;
int status;
pid_t retval;
int i;
printf("You called me with %d arguments.\n", argc);
for (i=0; i<argc; i++) {
printf("Arg %d: %s\n", i, argv[i]);
}
child = fork();
printf("Hello! I am %d, my parent is %d.\n",
getpid(), getppid());
if (child == 0) {
/* We're the child */
execve("/bin/ls", argv, envp);
sleep(3);
printf("Child all done!\n");
} else {
/* We're the parent */
retval = wait(&status);
printf("Parent all done! Child %d returned %d.\n",
(int) retval, WEXITSTATUS(status));
}
return 42;
}
- int execve(const char *filename, char *const argv[], char *const envp[]) - this system call executes the program pointed to by filename - The child process becomes independent from its parent -- a new program - argv[] is an array of strings passed to the new program. The values are loaded into the array by execve not the kernel. - envp[] is an array of strings of the form key=value which are passed as environment to the new program
- What happens when the if statement executes - execve creates a new program -- an independent process and passes arguments to the "ls" program. - execve stops the new process after it has completed.
- Some interesting points about main(int argc, char* argv[], char* envp[]) - Notice that the size of the arrays are not defined. We have to use argc to get this information. Not good programming practice but is accepted because it is grandfathered from the early days of the c language. - arg[0] is always the name of the program.