2 Systems Programming
2 Systems Programming
◦ Also a process can wait for its children to end ◦ Code stays the same, execution continues from the next
line for child and parent
◦ A process can be terminated while its children is left
running
◦ Two processes will have the same value for all variables
◦ If parent of a process is terminated while the process is at the creation time, but they are not shared and may
still running: diverge
The child becomes orphan
Child processes are immediately adopted by init ◦ Only way to differentiate between child and parent is
the return value of fork() system call
Child processes will continue running under init
without any issues
Once finished, init will terminate the child ◦ If there is an error fork() returns a negative number
and child process will not be created
◦ When a child process is finished and its parent is not
waiting, the process becomes zombie process
◦ fork() returns a positive number to the parent process.
Reason behind this behavior is to allow parent pro- This number is the pid of the child that is created
cess to later read the return value of the child pro-
cess
◦ fork() returns 0 to the child process, if necessary, child
In modern systems child is almost terminated in can access pid of its parent by called getppid().
this state and takes up very few amount of re-
sources
Parent can call to terminate the child ◦ The following program will create a child process, both
child and the parent will display process information
If parent never calls wait and exists, init will reap
the zombie
Even if a parent constantly creates children with- int pid = fork();
out waiting for them to finish, system will run out
if(pid == -1) {
of process numbers before running out of memory
perror("Fork error");
return -1;
Getting information }
else if(pid == 0) {
◦ It is possible to get process id (pid) of the current pro- printf("I am the child process with PID: %d, PPID: %d
cess by calling getpid() system call }
else {
◦ Parent process id (ppid) can be accessed using printf("I am the parent process with PID: %d, PPID: %
getppid() system call }
1/3
Waiting for child process Executing other applications
! <wait.h> <sys/types.h> ! <unistd.h>
◦ Parent processes can wait for its child processes to finish ◦ It is possible to replace currently running code with an-
◦ This allows parent to get return code of the child as well other
waiting for it finish
◦ Effectively this switches to another application
◦ pid = wait(status ) is used for this task, pid is the
child that is finished. In case of an error pid will be neg- ◦ The functions that are used to perform this operation
ative. This includes when there is no children to wait. is called exec family system calls
status is the termination status of the child. There
are two macros to analyze this status. It is a pointer to
◦ If there are no errors, an exec call will not terminate
integer and can be left NULL if not needed. ◦ When the executed application finishes, the child pro-
◦ In order to determine if the child process has crashed, cess will be terminated
WIFEXITED(status macro can be used. If this macro
returns 0 the child has crashed
◦ Unless specified otherwise, file descriptors, environ-
ment, and signals will not be modified when the process
◦ Return code of a child that has returned (as opposed is executed
to crashing) can be obtained by WEXITSTATUS(status )
macro ◦ execl or execlp(progam , arguments ..., NULL): ex-
ecutes a program from current path (execl) or from
◦ The following code will run a child process, wait for it the system path (execlp) by specifying arguments as
to exit and at the end it will show the state of the child. parameters to this function. First argument should be
Child will ask a value and divide 10 to that value and the name of the program while last argument should be
returns the result. If provided value is 0, child will crash NULL.
due to division by 0.
◦ execv or execvp(program , arguments ): executes a
if(fork()) { program by giving out an argument vector (NULL ter-
int status;
minated). Useful when arguments are constructed step
wait(&status);
by step.
if(WIFEXITED(status)) {
◦ Following code segment will execute ls -l command
printf("Child has finished with %d\n",
which will display detailed list of files in the current
WEXITSTATUS(status)); directory:
}
else { if(fork()) {
printf("Child has crashed.\n"); wait(NULL);
} }
} else {
else { execlp("ls", "ls", "-la", NULL);
int x; perror("Cannot run ls");
scanf("%d", &x); }
return 10 / x;
} Environment variables
! <stdlib.h>
Process tree ◦ Used to store variable that are passed to child processes
◦ Important tool to understand what is going on ◦ Useful to probe slow changing system info
◦ sleep(seconds ) makes the process sleep for given sec- ◦ They are not automatically updated, only newly cre-
onds, good for testing but should never be used for pro- ated direct children of the modifier will be affected
cess synchronization
◦ C Library provides these functions
◦ Zombie and orphan graphs
◦ Trace the following:
◦ getenv(name ): returns the value for the given variable
name. Environment variables are generally capitalized
for(int i=0; i<4; i++) { and cannot contain = sign
int pid = fork();
◦ setenv(name , value , overwrite ): sets the value of
if(pid && i%2) the variable with the given name. If variable exists and
return 0; overwrite parameter is set to 0, it will not be changed.
2/3
◦ exec family functions that have an additional e at the int main() {
end (like execvpe) takes an additional vector whose signal(SIGINT, &sig_int);
members are in form of VAR=value. This vector will while(1) {
be used for environment variables. printf("Sleeping...");
sleep(1);
◦ Following code prints the name of the current user: }
Signals
! <signal.h>
void sig_int(int) {
printf("Interrupted...\n");
exit(0);
}
3/3