The tree-like process structure in Linux provides great convenience for management processes. Both kernel-based process management and user-based process management have benefited a lot, and it is also useful for auditing, no matter what process is running, there will be a clue that it will not be broken and tied to the system. In the case of the whole system, the kernel is started first, and then the kernel Thread 0 derives the init, and then the init derives everything, a little like God's creation... however, if you are Satan, you can break the process out of this clue and only associate it with the linked list or tree of scheduling, so that your process becomes completely uncontrolled, at the same time, it has become a real orphan and no one has adopted it.
Backtrace or GDB coredump can get the function call stack. On Feng's machine, the stacks are linearly stacked, but processes can be run in time-based mode (the concurrent machine and the Von noriman machine are two different types. The current OS implementation is simulating concurrency ON THE Von's machine, which is a time-based operation ), therefore, if you think of a hardware machine as a platform, all processes constitute a tree, similar to backtrace. You can get the calling process of the current process, that is, the parent process, with the support of the operating system, in Linux, It is very convenient to use the proc file system. The following code obtains the process PID and process name of the caller of a shell script. The same code can be implemented in C, just replace $ with getpid.
PID =$ $
Name = 'cat/proc/$ PID/STAT | awk '{print $2 }''
Ppid = 'cat/proc/$ PID/STAT | awk '{print $4 }''
Pname = 'cat/proc/$ ppid/STAT | awk '{print $2 }''
# At This Point, name indicates the name of the Current Shell, while pname indicates the name of the caller. PID indicates the PID of the current shell, and ppid indicates the PID of the caller. (Note: If you use these lines of code, the first line of shell script should be strict #! /Bin/bash, otherwise the script will be executed by bash line by line, and the name of the parent process will always be Bash ). How can we list the relationships between all processes in the system like the pstree command? After strace pstree found that pstree is actually the information of the/proc file system read, and then organized together, the Linux kernel exports a lot of useful information in the/proc/Pid/STAT file, which contains information about the parent process, see/proc/Pid/STAT kernel functions (located in FS/proc/array. c ):
Static int do_task_stat (struct task_struct * task, char * buffer, int whole)
{
...
Ppid = pid_alive (task )? Task-> group_leader-> real_parent-> tgid: 0;
...
Res = sprintf (buffer, "% d (% s) % C % d % lu/
% Lu % LD % d 0% LlU % lu % LD % lu/
% Lu % d % lu % LlU/N ",
Task-> PID, // export your own PID
Tcomm, // export the process name
State, // export the Process status
Ppid, // export the parent process PID
...
);
...
}
Therefore, we only need to find the fourth field of/proc/Pid/STAT, and the above script is available. Next, let's take a look at the principle of pstree. Since we can find any process parent process and all processes in Linux are the same root, we only need to connect all processes, we have two equivalent methods, both of which use a large array and do not care about the complexity of space. They aim to reveal the principle without considering anything else:
Method 1: int proc [32768] [32768]; // The process PID is used horizontally and the process parent process PID is used vertically.
Method 2: int proc [32768]; // the index of the array element is the PID of the process, and its value is the PID of the parent process.
Int main (INT argc, char ** argv)
{
File * FP, * FPP;
File * fp = popen ("ls/proc/| egrep '^ [0-9] + $'", "R ");
Fread (BUF, 1024, 1, FP );
Foreach (I, Buf ){
FPP = popen ("cat/proc/I/STAT | awk '{print $4}'", "R ");
Read (ppid );
Method 1: Proc [I] [ppid] = 1;
Method 2: Proc [I] = ppid;
}
Return 0;
}
In this way, all processes are connected. Finally, let's take a look at the bitmap of the export process status, which is also good:
Static const char * task_state_array [] = {
"R (running)",/* 0 */
"S (sleeping)",/* 1 */
"D (Disk sleep)",/* 2 */
"T (stopped)",/* 4 */
"T (tracing stop)",/* 8 */
"Z (zombie)",/* 16 */
"X (dead)"/* 32 */
};
// Designing a process state to a simple shift to the left has many benefits. The most important thing is that the process state conversion process is the state machine conversion process, A simple shift can make the process state exclusive and easy to switch. Moving to the left also does not affect other shifts to the right.
Static inline const char * get_task_state (struct task_struct * TSK)
{
Unsigned int state = (tsk-> State & (task_running | // each process can be in only one State at a time. This is exclusive.
Task_interruptible |
Task_uninterruptible |
Task_stopped |
Task_traced) |
(Tsk-> exit_state & (exit_zombie |
Exit_dead ));
Const char ** P = & task_state_array [0];
While (state ){
P ++;
State> = 1; // The difference between 1 in the State and the rightmost position determines the elements in the Process status.
}
Return * P;
}