Objective
has been the Linux kernel plot, has been looking at the Linux kernel related books and code, but each time to the end of the change of interest and abandoned. This time finally calm down to the Linux kernel related code to take a good look, is a precipitate of their own it. Since the previous job is to do distributed scheduling this piece of things, but also a bit of distributed file system-related internship experience, so reading the Linux kernel Code of the center of gravity may be to the scheduling and file system of the two large tilt.
Personal feeling read Linux kernel is still quite necessary, in fact, now a variety of distributed framework, a variety of cloud computing, in fact, a lot of ideas are borrowed from the Linux kernel. But now people are more impetuous, are more quick-buck, are eager to put what distributed framework completely research, and
The underlying foundation is ignored. But to the back and just stay in the theory, and do not know how to go deep.
Linux Timers
Linux uses the system timer to calculate elapsed time, using global jiffies to record the total number of beats that have been generated since the system started. Because all the clocks of the Linux system, the scheduling of the process, and the load balancing of the running queue all depend on the timer.
So the addition of the Linux timer and the lookup performance requirements of the timeout timer are particularly important, so it is important to be able to find the timeout timer in O (1), and see the logic of adding this block to the Linux kernel timer. Have to say that this piece of code
It's good to write, and the algorithm is very simple.
From the point of view of the timeout timer, there are some ways to do this:
1. The most easy to think of, but also is the time complexity of the highest: maintenance of a timer chain, each time you insert a timer, you can insert the timer at the top of the list, so that the insertion time responsible for the degree of O (1), but the search must be traversed,
The time of responsibility will be O (N).
2. Maintain a timer array in which each element in the array is ordered in strict accordance with the timeout jiffies. In this way, you can use a binary lookup to find the time complexity of O (LgN). However, for the insertion and deletion of timers, the time complexity is high,
The element must be moved, and the time complexity is in O (N).
3. Use heap or red-black tree so that the insertion, find and delete time complexity will be O (LgN). It's still acceptable, but the programming is a little more complicated.
4. The implementation of the Linux kernel, the insertion time complexity O (N), find and delete time complexity of O (1), performance is very good. And all of them are kernel usage scenarios, and inserts are definitely much lower in comparison to lookups. For example, a timer's
Timeout time is 10jiffies relative to now, so it is 10 jiffies that involves 10 lookups but only one insertion and deletion.
Linux Timer Insert Code
Looking at the insertion logic of the Linux timer, you will find that it is expected to do a lot of optimization when inserting, and you will find that the timeout timer can be found in the O (1) complexity.
The logic of the preceding judgments is needless to say, and this piece will tell the core code. The first is to determine the current timer with insertion is not appropriate, if legally inserted into the list head. Then, it's optimization. The core code is as follows:
while (P->next && p->next->jiffies < p->jiffies) { P->jiffies-= p->next->jiffies; fn = P->fn; P->FN = p->next->fn; P->NEXT->FN = fn; Jiffies = p->jiffies; P->jiffies = p->next->jiffies; P->next->jiffies = jiffies; p = p->next;}
P is the timer-linked table header pointer, the code in the core of the logic is p->jiffies-= p->next->jiffies; each timer real timeout time is the sum of all the previous timer jiffies value and its own jiffies. and the list is ordered according to the jiffies value.
But there is still one problem in this code, if you think about it carefully. If the element that you just started inserting is small, the elements that are inserted later are larger, which is really no problem. However, if the previously inserted element is larger, the later inserts are smaller.
If, insert 1, 2, 3, 4, strict minimum initial insertion is not a problem, so the final list element values are 1, 1, 1, 1. OK, it must be normal, each time the jiffies expires, the value of the first element will be reduced by 1, to 0 will be cleared off,
and call the corresponding registration method.
However, there is a problem with subsequent insertions that are not the largest values in the current list, such as by 4, 3, 2, 1, or other order. As this example, the final list element values are 1, 2, 3, 4, respectively. That is, the last element would have to be 4jiffies due, and now it needs to be 10jiffies. Obviously unreasonable.
How to solve this problem, there is a way, the element is inserted into a definite position, then the value of the back element minus the value of the previous element. For example, 4 has been inserted, and the list is only 4, then insert 3, 3 is inserted before 4, and then all the elements behind the value minus the previous element.
So, after 3 is inserted into the list, the values in the list are 3, 1. After inserting 2, the value of the list element is 2, 3, 1, and the value of the element behind the 2 minus the meeting is 2, 1, 1. After inserting 1, the element values in the list are 1, 2, 1, 1, and then 2 minus 1.
So the final element value in the list is 1, 1, 1, 1.
while (P->next && p->next->jiffies < p->jiffies) { p->jiffies-= p->next-> jiffies; = P, fn; P->fn = p->next->fn; P->next->fn = fn; = p->jiffies; P->jiffies = p->next->jiffies; P->next->jiffies = jiffies; = P->Next;} if (p->next) { p->next->jiffies-= p->jiffies;}
Do not know why the source code in the contrary, there is no subsequent judgment,
if (p->next) { p->next->jiffies-= p->jiffies;}
Instead, the STI () function is called, and then the Add_timer function is ended. Did not look closely at the logic of the STI () function, but it was certain that the Linux kernel had done it, otherwise there would have been a bug.
However, the code in this piece is pretty good anyway. Can learn from, but before learning to understand the scene and its principle.
Linux kernel full Comment read Note 1:o (1) Time complexity find Timeout timer