Nginx source code analysis: ngx_queue_t
Source file path
src\core\Ngx_queue.h
src\core\Ngx_queue.c
Main role analysis
ngx_queue_t
Is Nginx
the doubly linked list provided .
A doubly linked list in the usual sense looks like this:
struct double_link_s {
int node;
double_link_t *prev;
double_link_t *next;
};
Contains three elements: node data data
, a pointer to the previous node and a pointer prev
to the next node next
.
Then there are the old-fashioned creation, insertion, deletion, etc. of doubly linked lists. I won’t go into details, just google it yourself.
In fact, if you take a closer look, you will find that the operations on doubly linked lists are basically centered prev
and next
unfolded, and data
have little to do with node data .
Therefore, abstracting the operation of the doubly linked list and forming an abstraction that has nothing to do with the nodes of the linked list can help us better operate the doubly linked list of various node types.
This feature is only linked list prev
and next
two variables, there is no representation of member variables list node. Therefore, this kind of linked list is also called a lightweight linked list .
At the same time, because this kind of linked list has no node member variables, it needs to exist as a member variable of a structure with node variables. In this case, this kind of linked list is called a hosted linked list , and the structure where the linked list is located is called a host .
Take a chestnut, it grows like this:
typedef double_link_s double_link_t;
struct double_link_s {
double_link_t *prev;
double_link_t *next;
};
struct node_s {
int node;
double_link_t link;
}
Simply put, if you want to use the structure as a linked list node, then add this lightweight linked list to itself as a member variable .
The schematic diagram is as follows:
In this way, the operation linked list is a lightweight linked list in the operation linked list, therefore, a general linked list structure can be defined.
In Nginx
, this general doubly linked list structure is ngx_queue_t
. This is not Nginx
invented, and Linux
this kind of linked list is also used in the kernel.
data structure
ngx_queue_t
According to the above analysis, it is very simple to define a lightweight linked list.
typedef struct ngx_queue_s ngx_queue_t;
struct ngx_queue_s {
ngx_queue_t *prev;
ngx_queue_t *next;
};
ngx_queue_t
Management and use
Since it is a doubly linked list, the basic operations on doubly linked lists are the same. Therefore, there is no need to explain more, just look at the source code.
ngx_queue_t
initialization
#define ngx_queue_init(q) \
(q)->prev = q; \
(q)->next = q
Use ngx_queue_t
the variable of the type to q
initialize the linked list. Because it is initialized, the prev
sum next
points to itself. q
As an empty node for managing the entire linked list.
Determine ngx_queue_t
whether it is empty
#define ngx_queue_empty(h) \
(h == (h)->prev)
Insert operation
#define ngx_queue_insert_head(h, x) \
(x)->next = (h)->next; \
(x)->next->prev = x; \
(x)->prev = h; \
(h)->next = x
Although the name of the macro is called insert_head
, it can actually be a general operation for inserting. So, in the source code
#define ngx_queue_insert_after ngx_queue_insert_head
There is no difference from the normal double-linked list insertion operation.
How to get the linked list node
One problem that cannot be avoided when using a boarding linked list is how to obtain the data of a node according to the linked list.
The basic idea to solve here is as follows:
- The host linked list is a member variable of the linked list node structure. Although the structure may be spatially discontinuous due to alignment issues, the entire structure itself can still be regarded as a continuous memory area.
- Therefore, you can use a
offsetof
macro to calculate the offset of the member variables of the host linked list relative to the starting position of the structure- The starting address of the host list-the offset of the member variables of the host list from the beginning of the structure = the start address of the structure
Therefore, ngx_queue_t
the above method is used to obtain node data
#define ngx_queue_data(q, type, link) \
(type *) ((u_char *) q - offsetof(type, link))
Among them q
is the variable type
of the host list, the type of the structure where the host list is located, and the name of the variable link
in the type
structure of the host list .
This macro returns the first address of the host structure.
Get the intermediate node of the doubly linked list
This is an old stalk of doubly linked list operations, that is, using double pointers, the moving speed is twice as fast. When the fast pointer reaches the end, the slower is the middle position.
The source code is as follows
ngx_queue_t *
ngx_queue_middle(ngx_queue_t *queue)
{
ngx_queue_t *middle, *next;
middle = ngx_queue_head(queue);
if (middle == ngx_queue_last(queue)) {
return middle;
}
next = ngx_queue_head(queue);
for ( ;; ) {
middle = ngx_queue_next(middle);
next = ngx_queue_next(next);
if (next == ngx_queue_last(queue)) {
return middle;
}
next = ngx_queue_next(next);
if (next == ngx_queue_last(queue)) {
return middle;
}
}
}
Of course, there are other operations, such as sorting, removing, and so on. It is basically the same as the regular doubly linked list operation.
It will not be described in detail here.