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

Process Part3


Contents

This chapter discusses processes in a Linux System.

Orphan Process

In the previous section we saw that a parent can create a child process. What happens if the parent exits after creating the child process. The child process does not die. Now we know that each process in Linux has a parent except the init process which is the first process. If the parent process dies then the child process is "adapted" by the init process whose id 1. We can illustrate this by the following program. The below program uses "fork" to create the child process.

File: orphan1.c
// A C program to demonstrate Zombie Process.
// Child becomes orphan after 10 seconds
// when parent process exits.
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
	// Fork returns process id
	// in parent process
	pid_t child_pid = fork();

	// Parent process
	if (child_pid > 0)
          {
              printf("\n In the parent process. Waiting for 10 seconds.\n ");
              fflush(stdout);
              sleep(10);
              printf("\n Parent process has exited.\n ");
              fflush(stdout);

          }
	// Child process
	else
          {
              printf("\n In the child process. Waiting for 60 seconds. \n");
              fflush(stdout);
              sleep(60);
              printf("\n Child process exiting.\n");
              fflush(stdout);
          }

	return 0;
}

We open 2 terminal windows. We run the program in the first terminal window and monitor the processes in the second terminal window.
[amittal@hills process]$ gcc orphan1.c -o orphan
[amittal@hills process]$ ./orphan1

 In the parent process. Waiting for 10 seconds.

 In the child process. Waiting for 60 seconds.

 Parent process has exited.
 [amittal@hills process]$
 Child process exiting.
[amittal@hills process]$



Initially both the parent and child processes are running. The one with
id of "3718893" is the parent.

amittal  3718893 3718463  0 16:31 pts/92   00:00:00 ./orphan1
amittal  3718894 3718893  0 16:31 pts/92   00:00:00 ./orphan1
amittal  3718899 3718490  0 16:31 pts/110  00:00:00 grep --color=auto orphan

After 10 seconds the parent process has exited. The
child process is adapted by the init process and it's
parent id becomes 1.

[amittal@hills process]$ ps -aef | grep "orphan"
amittal  3718894       1  0 16:31 pts/92   00:00:00 ./orphan1
amittal  3718906 3718490  0 16:32 pts/110  00:00:00 grep --color=auto orphan

After 60 seconds the child process has exited.
[amittal@hills process]$ ps -aef | grep "orphan"
amittal  3718935 3718490  0 16:33 pts/110  00:00:00 grep --color=auto orphan

Signals and Traps

A signal ( as it's name implies ) is an interrupt sent to a process notifying it that an important event has occurred. The process may ignore the signal or act upon it. We may have been using signals without being aware of it. Anytime we do "Ctrl-C" or use the "kill" command we are using a signal. Let's try some basic examples.

File: sig1.sh
echo "About to sleep"
sleep 60
echo "End of sleep"
[amittal@hills signals]$ chmod 777 sig1.sh
[amittal@hills signals]$ ./sig1.sh
About to sleep
^C[amittal@hills signals]$
The "sig1.sh" gets executed and basically sleeps for 60 seconds. We hit the "Ctrl-C" and that causes the INT signal to be sent to the process which causes the process to terminate. The below is another example. We execute a simple process that sleeps for 60 seconds in the backgroud.
[amittal@hills signals]$ sleep 60&
[1] 3792814
[amittal@hills signals]$ ps -aef | grep "sleep"
amittal  3792814 3776942  0 13:54 pts/54   00:00:00 sleep 60
amittal  3792824 3776942  0 13:55 pts/54   00:00:00 grep --color=auto sleep

We send the 9 ( SIGKILL ) signal to the process and that effectively
kills it. The format of the "kill" command is "kill signal processid" .

[amittal@hills signals]$ kill -9 3792814
[amittal@hills signals]$ ps -aef | grep "sleep"
amittal  3792828 3776942  0 13:55 pts/54   00:00:00 grep --color=auto sleep
[1]+  Killed                  sleep 60
[amittal@hills signals]$

We can use numbers of their word equivalents for sginals. We can get a listing of the different signals on the hills server with the "kill -l" command.
[amittal@hills signals]$ kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX


Using the "SIGKILL" instead of the number 9.
[amittal@hills signals]$ sleep 60&
[1] 3794171
[amittal@hills signals]$ kill -SIGKILL 3794171
[amittal@hills signals]$ ps -aef | grep "sleep"
amittal  3794173 3776942  0 14:27 pts/54   00:00:00 grep --color=auto sleep
[1]+  Killed                  sleep 60
[amittal@hills signals]$

When a process receives a signal it performs a default action. So doing a Ctrl-C sends an interrupt signal which terminates the process. Let's say we did not want this. We can override this behavior.
File: trap1.sh
trap '' 1 2
echo "About to sleep"
sleep 60
echo "End of sleep"
In the above code we have the "trap" command. We can list some signals that will be trapped. Amongst those signals is the interrupt ( Ctl-C ) signal. The ' ' after trap means that no action is to be taken.
Hitting Ctrl-C does not terminate the process.

[amittal@hills signals]$ ./trap1.sh
About to sleep
^C
We can also have an action in the trap command.
File: trap2.sh
trap 'rm data.txt' 1 2
echo "About to sleep"
sleep 60
echo "End of sleep"
In the above we have the command to remove a file if the interrupt signal is received. We create a file called "data.txt" in our folder where the file "trap2.sh" resides. If we hit "Ctrl-C" then the file is removed.
[amittal@hills signals]$ ls
data.txt  sig1.sh  trap1.sh  trap2.sh

[amittal@hills signals]$ ./trap2.sh
About to sleep
^CEnd of sleep

The trap command is executed and the file "data.txt" is removed.
[amittal@hills signals]$ ls
sig1.sh  trap1.sh  trap2.sh

Note we cannot trap the signal 9 as that means we won't be able to kill the process at all which can be a problem for runaway processes.

Pipes

We have been using pipes as commands on the shell. A pipe is a series of processes conncect by a pipe. Example:
The output of "ls" goes to a pipe and the next process ( "grep" )
uses this as input. If there was another pipe after grep it will
receive the output of "grep".

[amittal@hills process]$ ls | grep "zomb"
zombie
zombie1
zombie1.c
The above is a use of unamed pipes. We can also have a filesystem object called named pipe. We create this with the "mkfifo" command.
On one terminal window create a named pipe called "mypipe" .
Then the output of ls is redirected to "mypipe". The function will
hang till the data is read.



[amittal@hills cs260a]$ cd process
[amittal@hills process]$ mkfifo mypipe

[amittal@hills process]$ ls
a.out    exec3    f3.c       zombie     zombie.c
exec1    exec3.c  mypipe     zombie1    zomibe1
exec1.c  f1.c     orphan     zombie1.c
exec2    f2       orphan1    zombie2
exec2.c  f2.c     orphan1.c  zombie2.c
[amittal@hills process]$ ls > mypipe



On another terminal go the same folder.
If we are in a different folder then the command
will not be able to find the file "mypipe" .

[amittal@hills cs260a]$ cat < mypipe
-bash: mypipe: No such file or directory
[amittal@hills cs260a]$ cd process/
[amittal@hills process]$ cat < mypipe
a.out
exec1
exec1.c
exec2
exec2.c

The mypipe is a file and if we do a "ls -l" on it
we will see the character "p" signifying that it
is of type "p". We can also remove it using the
normal "rm" command.


[amittal@hills process]$ ls -l my*
prw------- 1 amittal csdept 0 Apr 14 23:36 mypipe
[amittal@hills process]$ rm mypipe
[amittal@hills process]$ ls -l my*
ls: cannot access 'my*': No such file or directory

The concept of named pipes can be used by multiple processes to communicate with each other. One process writes to the pipe while the other process can read from it.

ulimit

There are limits on what resources a process can use. These limits can be managed by a tool called "ulimit". To see the current limits we can do "ulimit -a" ( the a is for all limits). On the hills server we get.
[amittal@hills process]$ ulimit -a
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 46959
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 46959
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
[amittal@hills process]$

The "file size" is "unlimited". If this value was 0 then this user cannot create a file. We also have limits for virtual memory, cpu time, the number of open files a process can have. The CPU time is the number of seconds allowed for a process. If we give a value after the option then that sets the new limit.
[amittal@hills process]$ ulimit -t 10

By default only the soft limits are output.
[amittal@hills process]$ ulimit -a
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 46959
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) 10
max user processes              (-u) 46959
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
[amittal@hills process]$


In the above we set the cpu time limit to be 10 seconds and then list the limits to check that the limit has been set. This limit is only valid for this session. If we open another putty session we will not see this change. We have hard limits and soft limits. The soft limit is the value that we can change and the hard limit is the absloute upper limit. The soft limit cannot be higher than the hard limit. We can find out the hard and soft limits with the command:
Soft limits
[amittal@hills process]$ ulimit -aS
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 46959
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) 10
max user processes              (-u) 46959
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
[amittal@hills process]$ ulimit -aH
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 46959
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 262144
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) unlimited
cpu time               (seconds, -t) 10
max user processes              (-u) 46959
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
[amittal@hills process]$

Hard Limits
[amittal@hills process]$ ulimit -aH
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 46959
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 262144
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) unlimited
cpu time               (seconds, -t) 10
max user processes              (-u) 46959
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Thee is a configuration file that keeps these limits. It is "/etc/security/limits.conf". We can view the output of this file. on the hills server.
[amittal@hills ~]$ cat /etc/security/limits.conf
# /etc/security/limits.conf
#
#This file sets the resource limits for the users logged in via PAM.
#It does not affect resource limits of the system services.
#
#Also note that configuration files in /etc/security/limits.d directory,
#which are read in alphabetical order, override the settings in this
#file in case the domain is the same or more specific.
#That means for example that setting a limit for wildcard domain here
#can be overriden with a wildcard setting in a config file in the
#subdirectory, but a user specific setting here can be overriden only
#with a user specific setting in the subdirectory.
#
#Each line describes a limit for a user in the form:
#
#            
#
#Where:
# can be:
#        - a user name
#        - a group name, with @group syntax
#        - the wildcard *, for default entry
#        - the wildcard %, can be also used with %group syntax,
#                 for maxlogin limit
#
# can have the two values:
#        - "soft" for enforcing the soft limits
#        - "hard" for enforcing hard limits
#
# can be one of the following:
#        - core - limits the core file size (KB)
#        - data - max data size (KB)
#        - fsize - maximum filesize (KB)
#        - memlock - max locked-in-memory address space (KB)
#        - nofile - max number of open file descriptors
#        - rss - max resident set size (KB)
#        - stack - max stack size (KB)
#        - cpu - max CPU time (MIN)
#        - nproc - max number of processes
#        - as - address space limit (KB)
#        - maxlogins - max number of logins for this user
#        - maxsyslogins - max number of logins on the system
#        - priority - the priority to run user process with
#        - locks - max number of file locks the user can hold
#        - sigpending - max number of pending signals
#        - msgqueue - max memory used by POSIX message queues (bytes)
#        - nice - max nice priority allowed to raise to values: [-20, 19]
#        - rtprio - max realtime priority
#
#                 
#

#*               soft    core            0
#*               hard    rss             10000
#@student        hard    nproc           20
#@faculty        soft    nproc           20
#@faculty        hard    nproc           50
#ftp             hard    nproc           0
#@student        -       maxlogins       4

# End of file
[amittal@hills ~]$
All the entries are commented out. That means the default values are used. As a user we cannot change the hard limit to have a higher value:
The "-n" is the number of open files. The hard value from above is 262144.
If we try to change the hard limit we will get an error.
[amittal@hills limits.d]$ ulimit -Hn 262145
-bash: ulimit: open files: cannot modify limit: Operation not permitted

Without the "H" or the "S" the ulimit with a value will
set both the hard and soft limits.