In order to get the corresponding host structure (process descriptor) pointer from the given PID value quickly, the kernel adopts the structure of the PID hash list. First, the following questions to understand: 1) Why the PID hash list only defines 2048 or 4096 items (determined by your memory size)? Is it best to define the maximum PID value directly? We all know that the quickest way to find is an array, which can be done in a constant time. If our PID maximum is 32768, then we can define a struct task_struct* name[32768], and the corresponding host structure can be found most quickly from the given PID value. This is the process descriptor pointer that points to the PID process. However, this is indeed an irrational approach. Although the maximum value of the process PID is 32768, the PID value we can use in the actual application is much lower than the average value. This can result in a lot of wasted physical space. If we use 2,768 pid, then there is 30000*4bytes space waste. 2) Special case requirements imagine a situation in which the kernel must reclaim all threads within a thread group with a given PID value, (the PID values of all threads within the thread group are the same) and cannot be done in the definition of the array as above. And what we're going to do is we have to organize this form of thread group (the same PID value) into a linked list. The node of this list is all the threads within this thread group. And the PID hash list can be very good to complete the above 1) 2) two points. Let's look at the definition and initialization process of the kernel for the PID hash list and the related operations. static struct Hlist_head *pid_hash[pidtype_max];
The system manually created an array of pointers containing PIDTYPE_MAX elements during initialization.
Used to hold a pointer to a hash bucket.
And the Pidhash_init function is called during Start_kernel to initialize the hash bucket.
303 void __init pidhash_init (void)
/* */
304 {
305 int I, J, Pidhash_size;
306 unsigned long megabytes = Nr_kernel_pages >> (20-page_shift);
307
308 Pidhash_shift = max (FLS (megabytes * 4));
309 pidhash_shift = Min (n, pidhash_shift);
310 pidhash_size = 1 << pidhash_shift;
311
312 PRINTK ("PID hash Table entries:%d (order:%d,%zd bytes) \ n",
313 Pidhash_size, Pidhash_shift,
314 Pidtype_max * pidhash_size * sizeof (struct hlist_head));
315 ###### #以上为桶的大小设置和桶中含有的entry个数设置
###### #dmesg结果显示: PID hash table entries:4096 (order:12, 16384 bytes)
###### #pidhash_size (bucket size): 4096*4bytes entries:4096
###### #也就是说桶中存有4096个指针, pointer pointing to struct HLIST_NODE structure
(i = 0; i < Pidtype_max; i++) {
317 Pid_hash[i] = Alloc_bootmem (Pidhash_size *
318 sizeof (* (pid_hash[i)));
###### #在系统启动期间slab和alloc分配器都还没有建立好
###### #采用allocbootmem内存分配器对系统初始化期间的内存进行分配
319 if (!pid_hash[i])
Panic ("Could not alloc pidhash!\n");
321 for (j = 0; J < Pidhash_size; J + +)
322 Init_hlist_head (&pid_hash[i][j]);
###### #将桶中指向struct hlist_node structure Pointer first is initialized to null
323}
After this function The PID hash list is initialized to complete. At the same time, the PID bitmap was also initialized during the Start_kernel. It is a simple and efficient form to use PID bitmap to manage the process PID number. (bit:0 represents this PID can use Bit:1 to represent that the PID is already occupied)
The system manually allocates space and initializes the bitmap that represents the PID number of the process during initialization.
- typedef struct PIDMAP {
- Wuyi atomic_t Nr_free;
- *page void;
- pidmap_t};
- The static pidmap_t pidmap_array[pidmap_entries] =
- 56 {[0 ... Pidmap_entries-1] = {Atomic_init (bits_per_page), NULL}};
During bitmap initialization: The Get_zeroed_page function is used to provide a physical page box for the bitmap, and this page box is implemented as initialized to 0.
Thus, a physical page box of size 4K, can represent the number of process number is: 4*1024*8=32768;
But one thing we want to be main: Because of the particularity of process number 0, we set it to be unavailable in advance, that is, the bitmap's No. 0 bit is set to 1, and the corresponding representation of the current available PID number minus 1.
- 326 void __init pidmap_init (void)
- /* */
- 327 {
- 328 int i;
- 329
- Pidmap_array->page = (void *) Get_zeroed_page (Gfp_kernel);
- 331 set_bit (0, Pidmap_array->page);
- 332 Atomic_dec (&pidmap_array->nr_free);
- 333
- 334/*
- 335 * Allocate PID 0, and hash it via all PID types:
- 336 */
- 337
- 338 for (i = 0; i < Pidtype_max; i++)
- 339 Attach_pid (current, I, 0);
- 340}
The code above uses the ATTACH_PID function to hash the NO. 0 process and hash it into a hash list bucket that has already been initialized.
We know that each process has: struct PID Pids[pidtype_max], and the hash list is linked by this structure.
In the above function, the PID structure is first searched by the Find_pid function in the hash list of the specified type and NR number. Returns a pointer to the struct PID if found otherwise null is returned.
The following code makes the corresponding action based on the return value of the find_pid.
1) PID is NULL, indicating that the new attach process descriptor containing the struct PID is the first element of the hash list, inserted after the head node, and the Pid_list field of the struct PID is set to null. struct List_head Pid_list is a connector that connects process descriptors that have the same NR number.
2) PID is not NULL, indicating that the corresponding hash list already exists in the Nr number "NR" Process descriptor, we only need to attach our process descriptor to the corresponding hash list of the process chain list.
We can also tell by the above two functions that the first process descriptor element of the hash list for all buckets (typically 4) of index NO. 0 is the process descriptor of process No. 0.
The action corresponding to the Attach_pid function is dettach_pid: The process descriptor where the PID is located is removed from the corresponding PID hash list, and the function is defined as follows:
- 192 void Fastcall Detach_pid (task_t *task, enum Pid_type type)
- /* */
- 193 {
- 194 int TMP, NR;
- 195
- 196 nr = __detach_pid (task, type);
- 197 if (!NR)
- 198 return;
- 199
- (tmp = Pidtype_max;--tmp >= 0;)
- 201 if (tmp! = Type && find_pid (tmp, NR))
- 202 return;
- 203
- 204 Free_pidmap (NR);
- 205}
The core function is __detach_pid (task,type)
- 166 Static fastcall int __detach_pid (task_t *task, enum Pid_type type)
- /* */
- 167 {
- 168 struct PID *pid, *pid_next;
- 169 int nr = 0;
- 170
- 171 PID = &task->pids[type];
- 172 if (!hlist_unhashed (&pid->pid_chain)) {
- 173
- 174 if (List_empty (&pid->pid_list)) {
- 175 NR = pid->nr;
- 176 Hlist_del_rcu (&pid->pid_chain);
- 177} else {
- 178 Pid_next = List_entry (Pid->pid_list.next,
- 179 struct PID, pid_list);
- */* Insert next PID from pid_list to hash */
- 181 Hlist_replace_rcu (&pid->pid_chain,
- 182 &pid_next->pid_chain);
- 183}
- 184}
- 185
- 186 List_del_rcu (&pid->pid_list);
- 187 Pid->nr = 0;
- 188
- 189 return NR;
- 190}
The function first determines whether the process that the task points to has been hashed into the PID hash list, noting that it is possible that the process chain list in the hash list.
If it is not a node of the hash list, it is removed directly from the list of processes in which it resides. Return to nr=0, we can see later, the Detach_pid function according to the NR value to determine whether the PID bitmap should be the corresponding PID bit clear 0, so as to enable the continuation can be used.
If you are a node in a hash list, you also need to determine
1) Whether this hash list node is the only node in the process chain list. If the NR is set to PID->NR and the node is deleted
2) If the hash list node is located in the Process chain table, there are other nodes. Then replace the node with the next node. Note that the value of NR is not set at this time. Which means that the returned nr=0
When returning from __datach_pid, the next task is to determine whether the PID corresponding to the PID bitmap in the corresponding bit clear 0
1) If nr=0, do not need clear 0 function to return directly. By the above we know that the function will return nr=0 in two cases:
One, the process linked list is non-null (the implication of this is that the PID is also used by the rest of the process/thread, not in the bitmap to release it;
Second, the deletion is the nr=0 process descriptor. This is also not required to be released in the bitmap, because the No. 0 PID is special and is not allowed to be used by other processes.
2) If NR is not equal to 0, also determine if there is such a process descriptor in the other type of hash list, and if so, it cannot be freed if it is in use.
If the above two steps are not return then it is necessary to the PID bitmap in the PID representation of the 0, for the system to use.
An understanding of the above code is prone to problems:
- (tmp = Pidtype_max;--tmp >= 0;)
- 201 if (tmp! = Type && find_pid (tmp, NR))
- 202 return;
Why only search other types of hash lists without processing the hash list of the type of PID we just deleted? Because the hash list of the type of the process descriptor you just deleted, we should durable the NR value to indicate whether the bitmap bit needs to be cleared.
If nr=0 then delete the process descriptor that is located in the process list is non-empty---do not have to delete
If the process chain list is empty then NR=PID-->NR we do not consider PID No. 0 then this NR must be non-0 so this type of hash list does not use this process number, you check other types of hash list is still used it.
If the other has one in use, OK does not delete the return. If not, then I'll clean the portal Pidbitmap the corresponding bit is set to 0.
Article Source: http://blog.chinaunix.net/uid-25538637-id-271546.html
[Reprint] Linux process management-----PID Hash List