The process list

To allow an efficient search through processes of a given type (for instance, all processes in a runnable state), the kernel creates several lists of processes. Each list consists of pointers to process descriptors. A list pointer (that is, the field that each process uses to point to the next process) is embedded right in the process descriptor's data structure. When you look at the C-language declaration of the task_struct structure, the descriptors may seem to turn in on themselves in a complicated recursive manner. However, the concept is no more complicated than any list, which is a data structure containing a pointer to the next instance of itself.

A circular doubly linked list (see Figure 3-3) links all existing process descriptors; we will call it the process list. The prev_task and next_task fields of each process descriptor are used to implement the list. The head of the list is the init_task descriptor referenced by the first element of the task array; it is the ancestor of all processes, and is called process 0 or swapper (see Section 3.4.2 later in this chapter). The prev_task field of init_task points to the process descriptor inserted last in the list.

Figure 3-3. The process list

Figure 3-3. The process list

The set_links and remove_links macros are used to insert and to remove a process descriptor in the process list, respectively. These macros also take care of the parenthood relationship of the process (see Section 3.2.3 later in this chapter).

Another useful macro, called for_each_task , scans the whole process list. It is defined as:

for (p = &init task ; (p = p->next task) != &init task ; )

The macro is the loop control statement after which the kernel programmer supplies the loop. Notice how the init_task process descriptor just plays the role of list header. The macro starts by moving past init_task to the next task and continues until it reaches init_task again (thanks to the circularity of the list).

Was this article helpful?

0 0

Post a comment