Processes Part1
Contents
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 ~]$