Home Linux Admin Introduction Directory Tree Disks/File Systems Memory Mgmt Monitoring Startup/ShutDown Logging in/out User Accounts Backups Processes Cron Packages Books

Processes Part1


Contents

This chapter discusses processes in a Linux Systems.

Process

A program is a file on a system consisting of machine language instructions. When we run the program, the instructions get loaded into memory and the CPU starts to execute the instructions one by one. Now we have a process. It will have an entry in the kernel process table that contains information about the process. Each process has a unique id assigned to it. We can see the process id by using the command "ps -aef" as an example.


[amittal@hills dev]$ ps -aef | grep "1437191"
amittal  1437191 1437190  0 01:07 pts/0    00:00:00 -bash
amittal  1522355 1437191  0 20:47 pts/0    00:00:00 ps -aef


The second column specifies the process id and the third column specifies the id of the parent process. In the above case we ran the command "ps -aef" so the shell created a child process that ran the command. Of course once the printing of the process information finishes the "ps -aef" process will end. If we look for the same process id again we will not see it. Notice that the parent id of the command is "1437191". If we keep tracing the parent id we will eventually hit the id of 1 which is the id of the first process that is started by Linux when it boots up.

[amittal@hills dev]$ ps -aef | grep "1437191"
amittal  1437191 1437190  0 01:07 pts/0    00:00:00 -bash
amittal  1542379 1437191  0 23:44 pts/0    00:00:00 ps -aef
amittal  1542380 1437191  0 23:44 pts/0    00:00:00 grep --color=auto 1437191
[amittal@hills dev]$ ps -aef | grep "1437190"
amittal  1437190 1437187  0 Dec18 ?        00:00:00 sshd: amittal@pts/0
amittal  1437191 1437190  0 Dec18 pts/0    00:00:00 -bash
amittal  1566074 1437191  0 05:22 pts/0    00:00:00 grep --color=auto 1437190
[amittal@hills dev]$ ps -aef | grep "1437187"
root     1437187    1363  0 Dec18 ?        00:00:00 sshd: amittal [priv]
amittal  1437190 1437187  0 Dec18 ?        00:00:00 sshd: amittal@pts/0
amittal  1566089 1437191  0 05:23 pts/0    00:00:00 grep --color=auto 1437187
[amittal@hills dev]$ ps -aef | grep "1363"
root        1363       1  0 Oct19 ?        00:05:43 /usr/sbin/sshd

We can check the process with the id of 1 with the following command.
[amittal@hills temp]$ ps -aef | grep "systemd" | head -n 1
root           1       0  0 Jan12 ?        00:36:01 /usr/lib/systemd/systemd --switched-root --system --deserialize 18
[amittal@hills temp]$



TO DO: Run the command "ps -aef" on the Unix shell. Find out it's parent id. Follow the parent id of that and so using the commands:
ps -aef | grep "PROCESS ID"
Make sure the final process id is 1 as shown in the above example.

The command "ps" lists the processes that are currently running. It has quite a few options. The "-a" and "-e" option list all the processes including the ones not created by the user. The "-f" does a full format listing. If we don't use "-f" then we will see a minimal listing.

Process Group


A process group, as it's name implies, is a group/collection of related processes. A process group has an id. A process will have a process group to which it belongs to and the process group id will refer to a process. Let's take an example. Find out the process id of the bash process on your putty session with the command:

[amittal@hills process]$ ps -aef |  grep "bash"
amittal  2233605 2233604  0 Dec23 pts/2    00:00:00 -bash


Once we have the id then run the following command( replacing the number 2233605 with your own id):


[amittal@hills process]$ ps  xo pid,ppid,pgid,sid,comm  | grep "2233605"
2233605 2233604 2233605 2233605 bash
2272044 2233605 2272044 2233605 ps
2272045 2233605 2272044 2233605 grep

The "xo" is user-defined format with the first column as process id.
The second column is parent id. The third column is group id. The fourth
column is the session id and the fifth is the command name.


When we have commands in a pipe then the processes for those commands are placed in a process group. In the above example the processes "ps" and "grep" have a process group id of "2272044". Their parent id is the id "2233605" of the shell. When Linux creates a process group and places the first process in that group; it assigns that process's id as the process group id. In the above case we have "ps" as the first process in the group so we have "2272044" ( ps's process id ) as the group id. This process is called the group leader. What if we just have a single process ? Then the process leader is the same process and it's group id is it's process id.

[amittal@hills temp]$ ps  xo pid,ppid,pgid,sid,comm
    PID    PPID    PGID     SID COMMAND
1596551       1 1596551 1596551 systemd
1596553 1596551 1596551 1596551 (sd-pam)
1596582 1596580 1596580 1596580 sshd
1596583 1596582 1596583 1596583 bash
1704520 1704518 1704518 1704518 sshd
1704521 1704520 1704521 1704521 bash
2515262 1704521 2515262 1704521 ps

The "ps" process has a group id of "2515262"
which is it's own process id.



Place the following file in a folder on the hills server.
File: f1.c
The folder can be of any name. On my system it is at:
/users/amittal/cs260a/process

We can also have a process group by a program using the "fork()" call to create child processes.

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{
    pid_t pid;
    switch(  pid = fork()  )
    {
        case -1:
            printf("fork failed");
            break;
        case 0:  //first child
            printf("\nI am the first child, my pid is %d", getpid());
            fflush(stdout);
            sleep( 60 ) ;
            break;
        default:    //parent
            //sleep(5); /** sleep is generating problems **/
            printf("\nI am the parent process, my pid is %d", getpid());
            printf("\ngenerating a new child");
            fflush(stdout);
            switch(pid = fork())
            {
                case -1:
                    printf("fork failed");
                    break;
                case 0: //second child
                    printf("\nI am, the second child, my pid is %d", getpid());
                    fflush( stdout ) ;
  		    sleep( 60 ) ;
                    break;
                default:  //parent
                    wait((int *)0);
                    printf("\nback to parent, my pid is %d \n", getpid());
                    printf( "Parent exiting\n" ) ;
            }
    }

    return 0;
}



This program is written in "C" but we don't know need to know "C" in detail in order to understand the program. The key call is "fork()". We can think of the program as a sequence of machine language instructions. When the program hits "fork" then a copy of the same program is run. The original program is called the parent and the copy is the child. Both programs are at the instruction "fork". Now in the parent the fork returns a value that is not zero and in the child the value is zero. In the code above the first child is created and sleeps for 60 seconds and then exits. The parent goes in the "default" section and creates a second child which also sleeps for 60 seconds. The parent does a "wait" to wait for the 2 child processes to finish before exiting. All these 3 processes are related and have the same process group id.

In this program the parent creates a child process that will sleep for 60 seconds. It then proeeds to create a second child process that will also sleep for 60 seconds. The parent will then wait for the child processes to finish. All 3 programs belong to the same group. Compile the program "f1.c" by using the command: "gcc f1.c". This will produce a file called "a.out" .
Open up 2 putty sessions and in the first run the program "a.out". In the second putty session run the command: "ps xo pid,ppid,pgid,sid,comm" . The below shows a sample partial output. The id's will be different on your system.



[amittal@hills process]$ ./a.out

I am the parent process, my pid is 2556833
generating a new child
I am the first child, my pid is 2556834
I am, the second child, my pid is 2556835

[amittal@hills temp]$ ps  xo pid,ppid,pgid,sid,comm
    PID    PPID    PGID     SID COMMAND
2556833 1596583 2556833 1596583 a.out
2556834 2556833 2556833 1596583 a.out
2556835 2556833 2556833 1596583 a.out



The parent process "2556833" created 2 other processes and we can see that the group id is "2556833". Why do we need the concept of process groups ? Let's say we have a program that takes an input and we run it in the shell. This program will wait for the user to input something. This process is the foreground process. If we run a program that creates child processes then the system should know about all these processes as they are foreground processes and can take input from the terminal. Process groups help in organizing these processes. We can also send a signal to a group of processes.

In one screen run the "./a.out" program:


[amittal@hills process]$ ./a.out

I am the parent process, my pid is 2557287
generating a new child
I am the first child, my pid is 2557288
I am, the second child, my pid is 2557289


From the above we can deduce that the process group id is "2557287".
Open up another putty session and run the command:


[amittal@hills temp]$ kill -- -2557287

On the original putty session we have the group processes terminated.
[amittal@hills process]$ ./a.out

I am the parent process, my pid is 2557287
generating a new child
I am the first child, my pid is 2557288
I am, the second child, my pid is 2557289
Terminated



Session Group

A session group contains process groups. It has an id which is the id of a process. When a process is first created by the shell it becomes a member of the session group of it's parent. Just as a process group takes on the id of the first process in the group the session id takes on the id of the first member of the session group called the session leader. Usually this is the id of the bash shell. A session is usually created by the login process.

Run the following commands in one Putty session.

[amittal@hills process]$ ./a.out &
[1] 2286089

[amittal@hills process]$ ./a.out

and in another Putty session run the following command:

[amittal@hills process]$ ps  xo    pid,ppid,pgid,sid,comm

Output:
    PID    PPID    PGID     SID COMMAND
1696855       1 1696855 1696855 systemd
1696856 1696855 1696855 1696855 (sd-pam)
2233604 2233602 2233602 2233602 sshd

2233605 2233604 2233605 2233605 bash

2281064 2281062 2281062 2281062 sshd
2281065 2281064 2281065 2281065 sftp-server
2281262 2281259 2281259 2281259 sshd
2281263 2281262 2281263 2281263 sftp-server

2286089 2233605 2286089 2233605 a.out
2286090 2286089 2286089 2233605 a.out
2286091 2286089 2286089 2233605 a.out

2286092 2233605 2286092 2233605 a.out
2286093 2286092 2286092 2233605 a.out
2286094 2286092 2286092 2233605 a.out



In the above we have the first group of parent child processes ( a.out ) with the group number of 2286089 and the second group with a different group id of 2286092. Both the groups have the same session id of 2233605. This id belongs to the "bash" shell process and since it was the first process in this session; it's process id is used as the session id in it's entry.

Sessions are used for job control. A session can have a controlling tty. At most one process group in a session can be a foreground process group. We can also kill all the processes in a session. This is something that is done when a logged in user, logs off or that session is terminated unexpectedly.

Job Control

We start a process or a group of processes by typing the name of the program at the shell. The shell runs this as a job. A job is assigned a number( usually small integer). Normally we run the process and wait for it to finish before typing anything in the shell again. This is a foreground process. We can also run processes in the background. In this case the shell prompt will come back right away.

Run the following commands. You may have to hit "Enter" again after giving the command
"./a.out &". The first number "[1]" is the job number. It is different from the
process id number( the process id refers to a single process ).

[amittal@hills process]$ ./a.out &
[1] 2322743
[amittal@hills process]$
i'm the parent process, my pid is 2322743
generating a new child
i'm the first child, my pid is 2322744

[amittal@hills process]$ jobs
[1]+  Running                 ./a.out &
[amittal@hills process]$ kill %1
[1]+  Terminated              ./a.out
[amittal@hills process]$ jobs
[amittal@hills process]$ ps -aef | grep "a.out"
amittal  2322765 2294816  0 08:18 pts/2    00:00:00 grep --color=auto a.out
[amittal@hills process]$


We can run a process in the background using the "&" symbol attached to the end of the process. We use the "jobs" command to list the jobs iin our current session and we can see that a job with an id of "1" got created. We can kill the job with the command "kill %1". We can use "jobs" or "ps" to make sure that the job got killed. We can also kill a process by giving it's id.


[amittal@hills process]$ sleep 30 &
[1] 2323094
[amittal@hills process]$ ps -aef | grep "sleep"
amittal  2323094 2294816  0 08:30 pts/2    00:00:00 sleep 30
amittal  2323096 2294816  0 08:30 pts/2    00:00:00 grep --color=auto sleep
[amittal@hills process]$ kill 2323094
[amittal@hills process]$ ps -aef | grep "sleep"
amittal  2323137 2294816  0 08:31 pts/2    00:00:00 grep --color=auto sleep
[1]+  Terminated              sleep 30



In the example above we are using the Linux shell command "sleep" to create our process in the background. After running it we are presented with the process id. We use "ps" to make sure that the process is running. We use the "kill" command to kill the process and then make sure that our process has ended.

TO DO:

Run the command "sleep 60" in the background 2 times. Find out the job
numbers and the process id numbers of the 2 processes. Use both the
"ps" and the "jobs" commands to obtain this information.



In the below session run we can see how the system is using process groups internally. We killed the job "1" and that kills the 3 processes in that job.

[amittal@hills process]$
[amittal@hills process]$ ./a.out &
[1] 2323604
[amittal@hills process]$
i'm the parent process, my pid is 2323604
generating a new child
i'm the first child, my pid is 2323605

[amittal@hills process]$ ps -aef | grep "a.out"
amittal  2323604 2294816  0 08:45 pts/2    00:00:00 ./a.out
amittal  2323605 2323604  0 08:45 pts/2    00:00:00 ./a.out
amittal  2323606 2323604  0 08:45 pts/2    00:00:00 ./a.out
amittal  2323626 2294816  0 08:45 pts/2    00:00:00 grep --color=auto a.out
[amittal@hills process]$ kill %1
[amittal@hills process]$ ps -aef | grep "a.out"
amittal  2323635 2294816  0 08:45 pts/2    00:00:00 grep --color=auto a.out
[1]+  Terminated              ./a.out



There are 3 states for a job: foreground, background and suspended. 1) To suspend a job use the "Ctrl-z" command on the shell.

[amittal@hills process]$ sleep 60
^Z
[1]+  Stopped                 sleep 60
[amittal@hills process]$ ps  xo pid,stat,ppid,pgid,sid,comm | grep "sleep"
2324195 T    2294816 2324195 2294816 sleep



2) To move a job in the foreground use the "fg" command".

[amittal@hills process]$ sleep 60 &
[1] 2324323
[amittal@hills process]$ fg %1
sleep 60



3) To move a job to the background use the "bg" command.


[amittal@hills process]$ sleep 60
^Z
[1]+  Stopped                 sleep 60
[amittal@hills process]$ bg %1
[1]+ sleep 60 &
[amittal@hills process]$ ps -aef | grep "sleep"
amittal  2324384 2294816  0 09:06 pts/2    00:00:00 sleep 60
amittal  2324387 2294816  0 09:06 pts/2    00:00:00 grep --color=auto sleep
[amittal@hills process]$ ps -aef | grep "sleep"
amittal  2324384 2294816  0 09:06 pts/2    00:00:00 sleep 60
amittal  2324403 2294816  0 09:06 pts/2    00:00:00 grep --color=auto sleep
[amittal@hills process]$ ps -aef | grep "sleep"
amittal  2324425 2294816  0 09:07 pts/2    00:00:00 grep --color=auto sleep
[1]+  Done                    sleep 60


In the example above we start a process "sleep 60" and then suspend it. We then move the process/job to the background using the "bg %1" command. If we suspend a job we can either move it to the background or to the foreground.

[amittal@hills ~]$ sleep 60
^Z
[1]+  Stopped                 sleep 60
[amittal@hills ~]$ fg %1
sleep 60
[amittal@hills ~]$