PID Namespace

How to create PID namespaces:

      we can call clone() with CLONE_NEWPID flag to create PID namespaces:
      child_pid = clone(childFunc, child_stack, CLONE_NEWPID | SIGCHLD, argv[1]);
 
PID Namespace Hierarchy:


hehe

  A process can “see” only those processes contained in its own PID namespace and in the child namespaces nested below that PID namespace.
    If the parent of the child created by clone() is in a different namespace, the child cannot “see” the parent; therefore, getppid() reports the parent PID as being zero.
/proc/PID Directory:
     Within a PID namespace, the /proc/PID directories show information only about
processes within that PID namespace  or  processes within one of its descendant(子孙) namespaces.
Mount a proc filesystem:
   However, in order to make the /proc/PID directories that correspond to a PID namespace visible, the proc filesystem (“procfs” for short) needs to be mounted from within that PID namespace.
From a shell running inside the PID namespace (perhaps invoked via the system() library function), we can do this using a mount command of the following form:
 # mount -t proc proc /mount_point
“See” a Process:
Here, “see” means being able to make system calls that operate on specific PIDs.

e.g., using kill() to send a signal to process.
Processes in a child PID namespace cannot see processes that exist (only) in the parent PID namespace (or further removed ancestor namespaces).

PID returned by getpid():A process will have one PID in each of the layers of the PID namespace hierarchy starting from the PID namespace in which it resides through to the root PID namespace.Calls to getpid() always report the PID associated with the namespace in which the process resides.
Traditional init Process and Signals:
The traditional Linux init process is treated specially with respect to signals.
The only signals that can be delivered to init are those for which the process has established a signal handler.
All other signals are ignored.
This prevents the init process—whose presence is essential for the stable operation of the system —from being accidentally killed, even by the super user.
init Processes of  Namespaces and Signals:
 PID namespaces implement some analogous(类似) behavior for the namespace-specific init process.Other processes in the namespace (even privileged processes) can send only those signals for which the init process has established a handler. Note that (as for the traditional init process) the kernel can still generate signals for the PID namespace init process in all of the usual circumstances.such as hardware exceptions, terminal-generated signals such as SIGTTOU,and expiration of a timer.
Signals  from Ancestor Namespaces:
Signals can be sent to the PID namespace init process by processes in ancestor PID namespaces.Again, only the signals for which the init process has established a handler can be sent, with two exceptions: SIGKILL and SIGSTOP.When a process in an ancestor PID namespace sends SIGKILL and SIGSTOP to the init process, they are forcibly delivered (and can’t be caught).The SIGSTOP signal stops the init process; SIGKILL terminates it.
Termination of init Processes:Since the init process is essential to the functioning of the PID namespace, if the init process is terminated by SIGKILL (or it terminates for any other reason), the kernel terminates all other processes in the namespace by sending them a SIGKILL signal.
Connection between Processes and Namespaces:
Image
defination of nsproxy:  A structure to contain pointers to all per-process namespaces – fs (mount), uts, network, ipc, etc,shared by processes which share all namespaces. As soon as a single namespace is cloned or unshared, the nsproxy is copied.
struct nsproxy {
      atomic_t count;
struct uts_namespace *uts_ns;
struct ipc_namespace *ipc_ns;
struct mnt_namespace *mnt_ns;
struct pid_namespace *pid_ns;
struct net           *net_ns;
};
one thing should mentioned,:in this stucture, ‘count’ is the number of processes holding a reference.
The Operation System has defined init_nsproxy as default nsproxy:
struct nsproxy init_nsproxy = {
.count = ATOMIC_INIT(1),
.uts_ns = &init_uts_ns,
#if defined(CONFIG_POSIX_MQUEUE)|| defined(CONFIG_SYSVIPC)
  .ipc_ns = &init_ipc_ns,
        #endif
.mnt_ns = NULL,
.pid_ns = &init_pid_ns,
#ifdef CONFIG_NET
.net_ns = &init_net,
#endif
};

Process Identification Number:
Unix processes are always assigned a number to uniquely identify them in their namespace. This number is called the process identification number or PID for short. Each process generated with fork or clone is automatically assigned a new unique PID value by the kernel.PIDs are numbered sequentially in each PID namespace: the PID of a newly created process is normally the PID of the previously created process increased by one.Of course, there is an upper limit on the PID values; when the kernel reaches such limit, it must start recycling the lower, unused PIDs. By default, the maximum PID number is PID_MAX_LIMIT-1 (32,767 or 262143).
PIDs in PID :Namespaces add some additional complexity to how PIDs are managed.PID namespaces are organized in a hierarchy.
A Process May Have Multiple PIDs:When a new namespace is created, all PIDs that are used in this namespace are visible to the parent namespace, but the child namespace does not see PIDs of the parent .However this implies that some processes are equipped with more than one PID, namely, one per namespace they are visible in. This must be reflected in the data structures.
Global IDs:Global IDs are identification numbers that are valid within the kernel itself and in the initial global namespace. For each ID type, a given global identifier is guaranteed to be unique in the whole .The global PID and TGID are directly stored in the task_struct, namely, in the elements pid and tgid(Thread group ID):
typedef int                __kernel_pid_t;
typedef __kernel_pid_t     pid_t;
struct task_struct {

pid_t pid;
pid_t tgid;
     …
 
Linux associates a different PID with each process or lightweight process in the system. This approach allows the maximum flexibility, because every execution context in the system can be uniquely identified.On the other hand, Unix programmers expect threads in the same group to have a common PID. For instance, it should be possible to send a signal specifying a PID that affects all threads in the group.In fact, the POSIX 1003.1c standard states that all threads of a multithreaded application must have the same PID.
Local IDs:Local IDs belong to a specific namespace and are not globally valid. For each ID type, they are valid within the namespace to which they belong, but identifiers of identical type may appear with the same ID number in a different namespace.
Thread Group:To comply with POSIX 1003.1c standard, Linux makes use of thread groups. The identifier shared by the threads is the PID of the thread group leader , that is, the PID of the first lightweight process in the group.

The thread group ID of a thread group is called TGID.

Note that   every time  we call  getpid to require the process’s pid , what  the system return is  tgid value. know more detail, please click here.
 
Process Groups:Modern Unix operating systems introduce the notion of process groups to represent a job abstraction.
For example, in order to execute the command line:

  $ ls | sort | more

a shell that supports process groups, such as bash, creates a new group for the three processes corresponding to ls, sort, and more. In this way, the shell acts on the three processes as if they were a single entity (the job, to be precise).

One important feature is that it is possible to send a signal to every process in the group.Process groups are used for distribution of signals, and by terminals to arbitrate requests for their input and output.
Foreground Process Groups:A foreground process has read and write access to the terminal. Every process in the foreground receives SIGINT (^C ) SIGQUIT (^\ ) and SIGTSTP signals.
Background Process Groups:A background process does not have read access to the terminal. If a background process attempts to read from its controlling terminal its process group will be sent a SIGTTIN.
Group Leaders and Process Group IDs:Each process descriptor includes a field containing the process group ID.

Each group of processes may have a group leader, which is the process whose PID coincides with the process group ID.

Creation of a New Process Group:A newly created process is initially inserted into the process group of its parent.
The shell after doing a fork would explicitly call setpgid to set the process group of the child. The process group is explicitly set for purposes of job control. When a command is given at the shell prompt, that process or processes (if there is piping) is assigned a new process group.
Login Sessions:
  Modern Unix kernels also introduce login sessions.Informally, a login session contains all processes that are descendants of the process that has started a working session on a specific terminal — usually, the first command shell process created for the user.
All processes in a process group must be in the same login session. A login session may have several process groups active simultaneously; one of these process groups is always in the foreground, which means that it has access to the terminal. The other active process groups are in the background.When a background process tries to access the terminal, it receives a SIGTTIN or SIGTTOUT signal. In many command shells, the internal commands bg and fg can be used to put a process group in either the background or the foreground.
refrences: