COMS 4995 Advanced Systems Programming

Process Control

Process control

Displaying process hierarchy

ps axf     # display process tree

ps axfj    # with more info

ps axfjww  # even if lines wrap around terminal

View process information and hierarchy:

Creating processes

Consider the following simple shell program from APUE 1.6, Figure 1.7:

#include "apue.h"
#include <sys/wait.h>

int main(void)
{
    char    buf[MAXLINE];	/* from apue.h */
    pid_t   pid;
    int     status;

    printf("%% ");	/* print prompt (printf requires %% to print %) */
    while (fgets(buf, MAXLINE, stdin) != NULL) {
        if (buf[strlen(buf) - 1] == '\n')
            buf[strlen(buf) - 1] = 0; /* replace newline with null */

        if ((pid = fork()) < 0) {
            err_sys("fork error");
        } else if (pid == 0) {		/* child */
            execlp(buf, buf, (char *)0);
            err_ret("couldn't execute: %s", buf);
            exit(127);
        }

        /* parent */
        if ((pid = waitpid(pid, &status, 0)) < 0)
            err_sys("waitpid error");
        printf("%% ");
    }
    exit(0);
}

What happens if the parent process terminates before its children?

What happens if a child process has terminated, but the parent never calls waitpid()?

Memory Mappings Revisited

Recall that memory mappings can be private or shared. When a process calls fork() to create a child process, the parent’s private mappings are duplicated for the child process, whereas the child inherits the parent’s shared mappings.

In practice, the OS kernel does not eagerly create independent copies of private mappings. Instead, such mappings are marked read-only and shared between the processes until one of them makes a modification. At that point, the OS kernel creates the independent copy of the mapping. This optimization is known as Copy-On-Write (COW). Some mappings will never be modified and remain shared, e.g., program code.

COW is an especially performant optimization when you consider the fact that fork() is often followed by exec() which will replace the program image anyways.

The exec() system call also takes advantage of memory mappings. Loading the new program code into memory can be accomplished simply by mapping the executable file into the text region of the process’s address space.

Remote User Session

Here is the process hierarchy for an SSH login session:

root           1  Jan18   /lib/systemd/systemd --system --deserialize 43
root     2310948  Jan31    \_ sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
root     1525244  10:59        \_ sshd: hans [priv]
hans     1525262  10:59            \_ sshd: hans@pts/26
hans     1525264  10:59                 \_ -bash
hans     1556817  11:31                      \_ ps auxfww

Last Updated: 2024-02-04