mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
777 lines
26 KiB
ReStructuredText
777 lines
26 KiB
ReStructuredText
![]() |
.. SPDX-License-Identifier: GPL-2.0+
|
||
|
|
||
|
=====================
|
||
|
Linked Lists in Linux
|
||
|
=====================
|
||
|
|
||
|
:Author: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||
|
|
||
|
.. contents::
|
||
|
|
||
|
Introduction
|
||
|
============
|
||
|
|
||
|
Linked lists are one of the most basic data structures used in many programs.
|
||
|
The Linux kernel implements several different flavours of linked lists. The
|
||
|
purpose of this document is not to explain linked lists in general, but to show
|
||
|
new kernel developers how to use the Linux kernel implementations of linked
|
||
|
lists.
|
||
|
|
||
|
Please note that while linked lists certainly are ubiquitous, they are rarely
|
||
|
the best data structure to use in cases where a simple array doesn't already
|
||
|
suffice. In particular, due to their poor data locality, linked lists are a bad
|
||
|
choice in situations where performance may be of consideration. Familiarizing
|
||
|
oneself with other in-kernel generic data structures, especially for concurrent
|
||
|
accesses, is highly encouraged.
|
||
|
|
||
|
Linux implementation of doubly linked lists
|
||
|
===========================================
|
||
|
|
||
|
Linux's linked list implementations can be used by including the header file
|
||
|
``<linux/list.h>``.
|
||
|
|
||
|
The doubly-linked list will likely be the most familiar to many readers. It's a
|
||
|
list that can efficiently be traversed forwards and backwards.
|
||
|
|
||
|
The Linux kernel's doubly-linked list is circular in nature. This means that to
|
||
|
get from the head node to the tail, we can just travel one edge backwards.
|
||
|
Similarly, to get from the tail node to the head, we can simply travel forwards
|
||
|
"beyond" the tail and arrive back at the head.
|
||
|
|
||
|
Declaring a node
|
||
|
----------------
|
||
|
|
||
|
A node in a doubly-linked list is declared by adding a struct list_head
|
||
|
member to the data structure you wish to be contained in the list:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
struct clown {
|
||
|
unsigned long long shoe_size;
|
||
|
const char *name;
|
||
|
struct list_head node; /* the aforementioned member */
|
||
|
};
|
||
|
|
||
|
This may be an unfamiliar approach to some, as the classical explanation of a
|
||
|
linked list is a list node data structure with pointers to the previous and next
|
||
|
list node, as well the payload data. Linux chooses this approach because it
|
||
|
allows for generic list modification code regardless of what data structure is
|
||
|
contained within the list. Since the struct list_head member is not a pointer
|
||
|
but part of the data structure proper, the container_of() pattern can be used by
|
||
|
the list implementation to access the payload data regardless of its type, while
|
||
|
staying oblivious to what said type actually is.
|
||
|
|
||
|
Declaring and initializing a list
|
||
|
---------------------------------
|
||
|
|
||
|
A doubly-linked list can then be declared as just another struct list_head,
|
||
|
and initialized with the LIST_HEAD_INIT() macro during initial assignment, or
|
||
|
with the INIT_LIST_HEAD() function later:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
struct clown_car {
|
||
|
int tyre_pressure[4];
|
||
|
struct list_head clowns; /* Looks like a node! */
|
||
|
};
|
||
|
|
||
|
/* ... Somewhere later in our driver ... */
|
||
|
|
||
|
static int circus_init(struct circus_priv *circus)
|
||
|
{
|
||
|
struct clown_car other_car = {
|
||
|
.tyre_pressure = {10, 12, 11, 9},
|
||
|
.clowns = LIST_HEAD_INIT(other_car.clowns)
|
||
|
};
|
||
|
|
||
|
INIT_LIST_HEAD(&circus->car.clowns);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
A further point of confusion to some may be that the list itself doesn't really
|
||
|
have its own type. The concept of the entire linked list and a
|
||
|
struct list_head member that points to other entries in the list are one and
|
||
|
the same.
|
||
|
|
||
|
Adding nodes to the list
|
||
|
------------------------
|
||
|
|
||
|
Adding a node to the linked list is done through the list_add() macro.
|
||
|
|
||
|
We'll return to our clown car example to illustrate how nodes get added to the
|
||
|
list:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
static int circus_fill_car(struct circus_priv *circus)
|
||
|
{
|
||
|
struct clown_car *car = &circus->car;
|
||
|
struct clown *grock;
|
||
|
struct clown *dimitri;
|
||
|
|
||
|
/* State 1 */
|
||
|
|
||
|
grock = kzalloc(sizeof(*grock), GFP_KERNEL);
|
||
|
if (!grock)
|
||
|
return -ENOMEM;
|
||
|
grock->name = "Grock";
|
||
|
grock->shoe_size = 1000;
|
||
|
|
||
|
/* Note that we're adding the "node" member */
|
||
|
list_add(&grock->node, &car->clowns);
|
||
|
|
||
|
/* State 2 */
|
||
|
|
||
|
dimitri = kzalloc(sizeof(*dimitri), GFP_KERNEL);
|
||
|
if (!dimitri)
|
||
|
return -ENOMEM;
|
||
|
dimitri->name = "Dimitri";
|
||
|
dimitri->shoe_size = 50;
|
||
|
|
||
|
list_add(&dimitri->node, &car->clowns);
|
||
|
|
||
|
/* State 3 */
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
In State 1, our list of clowns is still empty::
|
||
|
|
||
|
.------.
|
||
|
v |
|
||
|
.--------. |
|
||
|
| clowns |--'
|
||
|
'--------'
|
||
|
|
||
|
This diagram shows the singular "clowns" node pointing at itself. In this
|
||
|
diagram, and all following diagrams, only the forward edges are shown, to aid in
|
||
|
clarity.
|
||
|
|
||
|
In State 2, we've added Grock after the list head::
|
||
|
|
||
|
.--------------------.
|
||
|
v |
|
||
|
.--------. .-------. |
|
||
|
| clowns |---->| Grock |--'
|
||
|
'--------' '-------'
|
||
|
|
||
|
This diagram shows the "clowns" node pointing at a new node labeled "Grock".
|
||
|
The Grock node is pointing back at the "clowns" node.
|
||
|
|
||
|
In State 3, we've added Dimitri after the list head, resulting in the following::
|
||
|
|
||
|
.------------------------------------.
|
||
|
v |
|
||
|
.--------. .---------. .-------. |
|
||
|
| clowns |---->| Dimitri |---->| Grock |--'
|
||
|
'--------' '---------' '-------'
|
||
|
|
||
|
This diagram shows the "clowns" node pointing at a new node labeled "Dimitri",
|
||
|
which then points at the node labeled "Grock". The "Grock" node still points
|
||
|
back at the "clowns" node.
|
||
|
|
||
|
If we wanted to have Dimitri inserted at the end of the list instead, we'd use
|
||
|
list_add_tail(). Our code would then look like this:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
static int circus_fill_car(struct circus_priv *circus)
|
||
|
{
|
||
|
/* ... */
|
||
|
|
||
|
list_add_tail(&dimitri->node, &car->clowns);
|
||
|
|
||
|
/* State 3b */
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
This results in the following list::
|
||
|
|
||
|
.------------------------------------.
|
||
|
v |
|
||
|
.--------. .-------. .---------. |
|
||
|
| clowns |---->| Grock |---->| Dimitri |--'
|
||
|
'--------' '-------' '---------'
|
||
|
|
||
|
This diagram shows the "clowns" node pointing at the node labeled "Grock",
|
||
|
which points at the new node labeled "Dimitri". The node labeled "Dimitri"
|
||
|
points back at the "clowns" node.
|
||
|
|
||
|
Traversing the list
|
||
|
-------------------
|
||
|
|
||
|
To iterate the list, we can loop through all nodes within the list with
|
||
|
list_for_each().
|
||
|
|
||
|
In our clown example, this results in the following somewhat awkward code:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
static unsigned long long circus_get_max_shoe_size(struct circus_priv *circus)
|
||
|
{
|
||
|
unsigned long long res = 0;
|
||
|
struct clown *e;
|
||
|
struct list_head *cur;
|
||
|
|
||
|
list_for_each(cur, &circus->car.clowns) {
|
||
|
e = list_entry(cur, struct clown, node);
|
||
|
if (e->shoe_size > res)
|
||
|
res = e->shoe_size;
|
||
|
}
|
||
|
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
The list_entry() macro internally uses the aforementioned container_of() to
|
||
|
retrieve the data structure instance that ``node`` is a member of.
|
||
|
|
||
|
Note how the additional list_entry() call is a little awkward here. It's only
|
||
|
there because we're iterating through the ``node`` members, but we really want
|
||
|
to iterate through the payload, i.e. the ``struct clown`` that contains each
|
||
|
node's struct list_head. For this reason, there is a second macro:
|
||
|
list_for_each_entry()
|
||
|
|
||
|
Using it would change our code to something like this:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
static unsigned long long circus_get_max_shoe_size(struct circus_priv *circus)
|
||
|
{
|
||
|
unsigned long long res = 0;
|
||
|
struct clown *e;
|
||
|
|
||
|
list_for_each_entry(e, &circus->car.clowns, node) {
|
||
|
if (e->shoe_size > res)
|
||
|
res = e->shoe_size;
|
||
|
}
|
||
|
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
This eliminates the need for the list_entry() step, and our loop cursor is now
|
||
|
of the type of our payload. The macro is given the member name that corresponds
|
||
|
to the list's struct list_head within the clown data structure so that it can
|
||
|
still walk the list.
|
||
|
|
||
|
Removing nodes from the list
|
||
|
----------------------------
|
||
|
|
||
|
The list_del() function can be used to remove entries from the list. It not only
|
||
|
removes the given entry from the list, but poisons the entry's ``prev`` and
|
||
|
``next`` pointers, so that unintended use of the entry after removal does not
|
||
|
go unnoticed.
|
||
|
|
||
|
We can extend our previous example to remove one of the entries:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
static int circus_fill_car(struct circus_priv *circus)
|
||
|
{
|
||
|
/* ... */
|
||
|
|
||
|
list_add(&dimitri->node, &car->clowns);
|
||
|
|
||
|
/* State 3 */
|
||
|
|
||
|
list_del(&dimitri->node);
|
||
|
|
||
|
/* State 4 */
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
The result of this would be this::
|
||
|
|
||
|
.--------------------.
|
||
|
v |
|
||
|
.--------. .-------. | .---------.
|
||
|
| clowns |---->| Grock |--' | Dimitri |
|
||
|
'--------' '-------' '---------'
|
||
|
|
||
|
This diagram shows the "clowns" node pointing at the node labeled "Grock",
|
||
|
which points back at the "clowns" node. Off to the side is a lone node labeled
|
||
|
"Dimitri", which has no arrows pointing anywhere.
|
||
|
|
||
|
Note how the Dimitri node does not point to itself; its pointers are
|
||
|
intentionally set to a "poison" value that the list code refuses to traverse.
|
||
|
|
||
|
If we wanted to reinitialize the removed node instead to make it point at itself
|
||
|
again like an empty list head, we can use list_del_init() instead:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
static int circus_fill_car(struct circus_priv *circus)
|
||
|
{
|
||
|
/* ... */
|
||
|
|
||
|
list_add(&dimitri->node, &car->clowns);
|
||
|
|
||
|
/* State 3 */
|
||
|
|
||
|
list_del_init(&dimitri->node);
|
||
|
|
||
|
/* State 4b */
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
This results in the deleted node pointing to itself again::
|
||
|
|
||
|
.--------------------. .-------.
|
||
|
v | v |
|
||
|
.--------. .-------. | .---------. |
|
||
|
| clowns |---->| Grock |--' | Dimitri |--'
|
||
|
'--------' '-------' '---------'
|
||
|
|
||
|
This diagram shows the "clowns" node pointing at the node labeled "Grock",
|
||
|
which points back at the "clowns" node. Off to the side is a lone node labeled
|
||
|
"Dimitri", which points to itself.
|
||
|
|
||
|
Traversing whilst removing nodes
|
||
|
--------------------------------
|
||
|
|
||
|
Deleting entries while we're traversing the list will cause problems if we use
|
||
|
list_for_each() and list_for_each_entry(), as deleting the current entry would
|
||
|
modify the ``next`` pointer of it, which means the traversal can't properly
|
||
|
advance to the next list entry.
|
||
|
|
||
|
There is a solution to this however: list_for_each_safe() and
|
||
|
list_for_each_entry_safe(). These take an additional parameter of a pointer to
|
||
|
a struct list_head to use as temporary storage for the next entry during
|
||
|
iteration, solving the issue.
|
||
|
|
||
|
An example of how to use it:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
static void circus_eject_insufficient_clowns(struct circus_priv *circus)
|
||
|
{
|
||
|
struct clown *e;
|
||
|
struct clown *n; /* temporary storage for safe iteration */
|
||
|
|
||
|
list_for_each_entry_safe(e, n, &circus->car.clowns, node) {
|
||
|
if (e->shoe_size < 500)
|
||
|
list_del(&e->node);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Proper memory management (i.e. freeing the deleted node while making sure
|
||
|
nothing still references it) in this case is left as an exercise to the reader.
|
||
|
|
||
|
Cutting a list
|
||
|
--------------
|
||
|
|
||
|
There are two helper functions to cut lists with. Both take elements from the
|
||
|
list ``head``, and replace the contents of the list ``list``.
|
||
|
|
||
|
The first such function is list_cut_position(). It removes all list entries from
|
||
|
``head`` up to and including ``entry``, placing them in ``list`` instead.
|
||
|
|
||
|
In this example, it's assumed we start with the following list::
|
||
|
|
||
|
.----------------------------------------------------------------.
|
||
|
v |
|
||
|
.--------. .-------. .---------. .-----. .---------. |
|
||
|
| clowns |---->| Grock |---->| Dimitri |---->| Pic |---->| Alfredo |--'
|
||
|
'--------' '-------' '---------' '-----' '---------'
|
||
|
|
||
|
With the following code, every clown up to and including "Pic" is moved from
|
||
|
the "clowns" list head to a separate struct list_head initialized at local
|
||
|
stack variable ``retirement``:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
static void circus_retire_clowns(struct circus_priv *circus)
|
||
|
{
|
||
|
struct list_head retirement = LIST_HEAD_INIT(retirement);
|
||
|
struct clown *grock, *dimitri, *pic, *alfredo;
|
||
|
struct clown_car *car = &circus->car;
|
||
|
|
||
|
/* ... clown initialization, list adding ... */
|
||
|
|
||
|
list_cut_position(&retirement, &car->clowns, &pic->node);
|
||
|
|
||
|
/* State 1 */
|
||
|
}
|
||
|
|
||
|
The resulting ``car->clowns`` list would be this::
|
||
|
|
||
|
.----------------------.
|
||
|
v |
|
||
|
.--------. .---------. |
|
||
|
| clowns |---->| Alfredo |--'
|
||
|
'--------' '---------'
|
||
|
|
||
|
Meanwhile, the ``retirement`` list is transformed to the following::
|
||
|
|
||
|
.--------------------------------------------------.
|
||
|
v |
|
||
|
.------------. .-------. .---------. .-----. |
|
||
|
| retirement |---->| Grock |---->| Dimitri |---->| Pic |--'
|
||
|
'------------' '-------' '---------' '-----'
|
||
|
|
||
|
The second function, list_cut_before(), is much the same, except it cuts before
|
||
|
the ``entry`` node, i.e. it removes all list entries from ``head`` up to but
|
||
|
excluding ``entry``, placing them in ``list`` instead. This example assumes the
|
||
|
same initial starting list as the previous example:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
static void circus_retire_clowns(struct circus_priv *circus)
|
||
|
{
|
||
|
struct list_head retirement = LIST_HEAD_INIT(retirement);
|
||
|
struct clown *grock, *dimitri, *pic, *alfredo;
|
||
|
struct clown_car *car = &circus->car;
|
||
|
|
||
|
/* ... clown initialization, list adding ... */
|
||
|
|
||
|
list_cut_before(&retirement, &car->clowns, &pic->node);
|
||
|
|
||
|
/* State 1b */
|
||
|
}
|
||
|
|
||
|
The resulting ``car->clowns`` list would be this::
|
||
|
|
||
|
.----------------------------------.
|
||
|
v |
|
||
|
.--------. .-----. .---------. |
|
||
|
| clowns |---->| Pic |---->| Alfredo |--'
|
||
|
'--------' '-----' '---------'
|
||
|
|
||
|
Meanwhile, the ``retirement`` list is transformed to the following::
|
||
|
|
||
|
.--------------------------------------.
|
||
|
v |
|
||
|
.------------. .-------. .---------. |
|
||
|
| retirement |---->| Grock |---->| Dimitri |--'
|
||
|
'------------' '-------' '---------'
|
||
|
|
||
|
It should be noted that both functions will destroy links to any existing nodes
|
||
|
in the destination ``struct list_head *list``.
|
||
|
|
||
|
Moving entries and partial lists
|
||
|
--------------------------------
|
||
|
|
||
|
The list_move() and list_move_tail() functions can be used to move an entry
|
||
|
from one list to another, to either the start or end respectively.
|
||
|
|
||
|
In the following example, we'll assume we start with two lists ("clowns" and
|
||
|
"sidewalk" in the following initial state "State 0"::
|
||
|
|
||
|
.----------------------------------------------------------------.
|
||
|
v |
|
||
|
.--------. .-------. .---------. .-----. .---------. |
|
||
|
| clowns |---->| Grock |---->| Dimitri |---->| Pic |---->| Alfredo |--'
|
||
|
'--------' '-------' '---------' '-----' '---------'
|
||
|
|
||
|
.-------------------.
|
||
|
v |
|
||
|
.----------. .-----. |
|
||
|
| sidewalk |---->| Pio |--'
|
||
|
'----------' '-----'
|
||
|
|
||
|
We apply the following example code to the two lists:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
static void circus_clowns_exit_car(struct circus_priv *circus)
|
||
|
{
|
||
|
struct list_head sidewalk = LIST_HEAD_INIT(sidewalk);
|
||
|
struct clown *grock, *dimitri, *pic, *alfredo, *pio;
|
||
|
struct clown_car *car = &circus->car;
|
||
|
|
||
|
/* ... clown initialization, list adding ... */
|
||
|
|
||
|
/* State 0 */
|
||
|
|
||
|
list_move(&pic->node, &sidewalk);
|
||
|
|
||
|
/* State 1 */
|
||
|
|
||
|
list_move_tail(&dimitri->node, &sidewalk);
|
||
|
|
||
|
/* State 2 */
|
||
|
}
|
||
|
|
||
|
In State 1, we arrive at the following situation::
|
||
|
|
||
|
.-----------------------------------------------------.
|
||
|
| |
|
||
|
v |
|
||
|
.--------. .-------. .---------. .---------. |
|
||
|
| clowns |---->| Grock |---->| Dimitri |---->| Alfredo |--'
|
||
|
'--------' '-------' '---------' '---------'
|
||
|
|
||
|
.-------------------------------.
|
||
|
v |
|
||
|
.----------. .-----. .-----. |
|
||
|
| sidewalk |---->| Pic |---->| Pio |--'
|
||
|
'----------' '-----' '-----'
|
||
|
|
||
|
In State 2, after we've moved Dimitri to the tail of sidewalk, the situation
|
||
|
changes as follows::
|
||
|
|
||
|
.-------------------------------------.
|
||
|
| |
|
||
|
v |
|
||
|
.--------. .-------. .---------. |
|
||
|
| clowns |---->| Grock |---->| Alfredo |--'
|
||
|
'--------' '-------' '---------'
|
||
|
|
||
|
.-----------------------------------------------.
|
||
|
v |
|
||
|
.----------. .-----. .-----. .---------. |
|
||
|
| sidewalk |---->| Pic |---->| Pio |---->| Dimitri |--'
|
||
|
'----------' '-----' '-----' '---------'
|
||
|
|
||
|
As long as the source and destination list head are part of the same list, we
|
||
|
can also efficiently bulk move a segment of the list to the tail end of the
|
||
|
list. We continue the previous example by adding a list_bulk_move_tail() after
|
||
|
State 2, moving Pic and Pio to the tail end of the sidewalk list.
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
static void circus_clowns_exit_car(struct circus_priv *circus)
|
||
|
{
|
||
|
struct list_head sidewalk = LIST_HEAD_INIT(sidewalk);
|
||
|
struct clown *grock, *dimitri, *pic, *alfredo, *pio;
|
||
|
struct clown_car *car = &circus->car;
|
||
|
|
||
|
/* ... clown initialization, list adding ... */
|
||
|
|
||
|
/* State 0 */
|
||
|
|
||
|
list_move(&pic->node, &sidewalk);
|
||
|
|
||
|
/* State 1 */
|
||
|
|
||
|
list_move_tail(&dimitri->node, &sidewalk);
|
||
|
|
||
|
/* State 2 */
|
||
|
|
||
|
list_bulk_move_tail(&sidewalk, &pic->node, &pio->node);
|
||
|
|
||
|
/* State 3 */
|
||
|
}
|
||
|
|
||
|
For the sake of brevity, only the altered "sidewalk" list at State 3 is depicted
|
||
|
in the following diagram::
|
||
|
|
||
|
.-----------------------------------------------.
|
||
|
v |
|
||
|
.----------. .---------. .-----. .-----. |
|
||
|
| sidewalk |---->| Dimitri |---->| Pic |---->| Pio |--'
|
||
|
'----------' '---------' '-----' '-----'
|
||
|
|
||
|
Do note that list_bulk_move_tail() does not do any checking as to whether all
|
||
|
three supplied ``struct list_head *`` parameters really do belong to the same
|
||
|
list. If you use it outside the constraints the documentation gives, then the
|
||
|
result is a matter between you and the implementation.
|
||
|
|
||
|
Rotating entries
|
||
|
----------------
|
||
|
|
||
|
A common write operation on lists, especially when using them as queues, is
|
||
|
to rotate it. A list rotation means entries at the front are sent to the back.
|
||
|
|
||
|
For rotation, Linux provides us with two functions: list_rotate_left() and
|
||
|
list_rotate_to_front(). The former can be pictured like a bicycle chain, taking
|
||
|
the entry after the supplied ``struct list_head *`` and moving it to the tail,
|
||
|
which in essence means the entire list, due to its circular nature, rotates by
|
||
|
one position.
|
||
|
|
||
|
The latter, list_rotate_to_front(), takes the same concept one step further:
|
||
|
instead of advancing the list by one entry, it advances it *until* the specified
|
||
|
entry is the new front.
|
||
|
|
||
|
In the following example, our starting state, State 0, is the following::
|
||
|
|
||
|
.-----------------------------------------------------------------.
|
||
|
v |
|
||
|
.--------. .-------. .---------. .-----. .---------. .-----. |
|
||
|
| clowns |-->| Grock |-->| Dimitri |-->| Pic |-->| Alfredo |-->| Pio |-'
|
||
|
'--------' '-------' '---------' '-----' '---------' '-----'
|
||
|
|
||
|
The example code being used to demonstrate list rotations is the following:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
static void circus_clowns_rotate(struct circus_priv *circus)
|
||
|
{
|
||
|
struct clown *grock, *dimitri, *pic, *alfredo, *pio;
|
||
|
struct clown_car *car = &circus->car;
|
||
|
|
||
|
/* ... clown initialization, list adding ... */
|
||
|
|
||
|
/* State 0 */
|
||
|
|
||
|
list_rotate_left(&car->clowns);
|
||
|
|
||
|
/* State 1 */
|
||
|
|
||
|
list_rotate_to_front(&alfredo->node, &car->clowns);
|
||
|
|
||
|
/* State 2 */
|
||
|
|
||
|
}
|
||
|
|
||
|
In State 1, we arrive at the following situation::
|
||
|
|
||
|
.-----------------------------------------------------------------.
|
||
|
v |
|
||
|
.--------. .---------. .-----. .---------. .-----. .-------. |
|
||
|
| clowns |-->| Dimitri |-->| Pic |-->| Alfredo |-->| Pio |-->| Grock |-'
|
||
|
'--------' '---------' '-----' '---------' '-----' '-------'
|
||
|
|
||
|
Next, after the list_rotate_to_front() call, we arrive in the following
|
||
|
State 2::
|
||
|
|
||
|
.-----------------------------------------------------------------.
|
||
|
v |
|
||
|
.--------. .---------. .-----. .-------. .---------. .-----. |
|
||
|
| clowns |-->| Alfredo |-->| Pio |-->| Grock |-->| Dimitri |-->| Pic |-'
|
||
|
'--------' '---------' '-----' '-------' '---------' '-----'
|
||
|
|
||
|
As is hopefully evident from the diagrams, the entries in front of "Alfredo"
|
||
|
were cycled to the tail end of the list.
|
||
|
|
||
|
Swapping entries
|
||
|
----------------
|
||
|
|
||
|
Another common operation is that two entries need to be swapped with each other.
|
||
|
|
||
|
For this, Linux provides us with list_swap().
|
||
|
|
||
|
In the following example, we have a list with three entries, and swap two of
|
||
|
them. This is our starting state in "State 0"::
|
||
|
|
||
|
.-----------------------------------------.
|
||
|
v |
|
||
|
.--------. .-------. .---------. .-----. |
|
||
|
| clowns |-->| Grock |-->| Dimitri |-->| Pic |-'
|
||
|
'--------' '-------' '---------' '-----'
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
static void circus_clowns_swap(struct circus_priv *circus)
|
||
|
{
|
||
|
struct clown *grock, *dimitri, *pic;
|
||
|
struct clown_car *car = &circus->car;
|
||
|
|
||
|
/* ... clown initialization, list adding ... */
|
||
|
|
||
|
/* State 0 */
|
||
|
|
||
|
list_swap(&dimitri->node, &pic->node);
|
||
|
|
||
|
/* State 1 */
|
||
|
}
|
||
|
|
||
|
The resulting list at State 1 is the following::
|
||
|
|
||
|
.-----------------------------------------.
|
||
|
v |
|
||
|
.--------. .-------. .-----. .---------. |
|
||
|
| clowns |-->| Grock |-->| Pic |-->| Dimitri |-'
|
||
|
'--------' '-------' '-----' '---------'
|
||
|
|
||
|
As is evident by comparing the diagrams, the "Pic" and "Dimitri" nodes have
|
||
|
traded places.
|
||
|
|
||
|
Splicing two lists together
|
||
|
---------------------------
|
||
|
|
||
|
Say we have two lists, in the following example one represented by a list head
|
||
|
we call "knie" and one we call "stey". In a hypothetical circus acquisition,
|
||
|
the two list of clowns should be spliced together. The following is our
|
||
|
situation in "State 0"::
|
||
|
|
||
|
.-----------------------------------------.
|
||
|
| |
|
||
|
v |
|
||
|
.------. .-------. .---------. .-----. |
|
||
|
| knie |-->| Grock |-->| Dimitri |-->| Pic |--'
|
||
|
'------' '-------' '---------' '-----'
|
||
|
|
||
|
.-----------------------------.
|
||
|
v |
|
||
|
.------. .---------. .-----. |
|
||
|
| stey |-->| Alfredo |-->| Pio |--'
|
||
|
'------' '---------' '-----'
|
||
|
|
||
|
The function to splice these two lists together is list_splice(). Our example
|
||
|
code is as follows:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
static void circus_clowns_splice(void)
|
||
|
{
|
||
|
struct clown *grock, *dimitri, *pic, *alfredo, *pio;
|
||
|
struct list_head knie = LIST_HEAD_INIT(knie);
|
||
|
struct list_head stey = LIST_HEAD_INIT(stey);
|
||
|
|
||
|
/* ... Clown allocation and initialization here ... */
|
||
|
|
||
|
list_add_tail(&grock->node, &knie);
|
||
|
list_add_tail(&dimitri->node, &knie);
|
||
|
list_add_tail(&pic->node, &knie);
|
||
|
list_add_tail(&alfredo->node, &stey);
|
||
|
list_add_tail(&pio->node, &stey);
|
||
|
|
||
|
/* State 0 */
|
||
|
|
||
|
list_splice(&stey, &dimitri->node);
|
||
|
|
||
|
/* State 1 */
|
||
|
}
|
||
|
|
||
|
The list_splice() call here adds all the entries in ``stey`` to the list
|
||
|
``dimitri``'s ``node`` list_head is in, after the ``node`` of ``dimitri``. A
|
||
|
somewhat surprising diagram of the resulting "State 1" follows::
|
||
|
|
||
|
.-----------------------------------------------------------------.
|
||
|
| |
|
||
|
v |
|
||
|
.------. .-------. .---------. .---------. .-----. .-----. |
|
||
|
| knie |-->| Grock |-->| Dimitri |-->| Alfredo |-->| Pio |-->| Pic |--'
|
||
|
'------' '-------' '---------' '---------' '-----' '-----'
|
||
|
^
|
||
|
.-------------------------------'
|
||
|
|
|
||
|
.------. |
|
||
|
| stey |--'
|
||
|
'------'
|
||
|
|
||
|
Traversing the ``stey`` list no longer results in correct behavior. A call of
|
||
|
list_for_each() on ``stey`` results in an infinite loop, as it never returns
|
||
|
back to the ``stey`` list head.
|
||
|
|
||
|
This is because list_splice() did not reinitialize the list_head it took
|
||
|
entries from, leaving its pointer pointing into what is now a different list.
|
||
|
|
||
|
If we want to avoid this situation, list_splice_init() can be used. It does the
|
||
|
same thing as list_splice(), except reinitalizes the donor list_head after the
|
||
|
transplant.
|
||
|
|
||
|
Concurrency considerations
|
||
|
--------------------------
|
||
|
|
||
|
Concurrent access and modification of a list needs to be protected with a lock
|
||
|
in most cases. Alternatively and preferably, one may use the RCU primitives for
|
||
|
lists in read-mostly use-cases, where read accesses to the list are common but
|
||
|
modifications to the list less so. See Documentation/RCU/listRCU.rst for more
|
||
|
details.
|
||
|
|
||
|
Further reading
|
||
|
---------------
|
||
|
|
||
|
* `How does the kernel implements Linked Lists? - KernelNewbies <https://kernelnewbies.org/FAQ/LinkedLists>`_
|
||
|
|
||
|
Full List API
|
||
|
=============
|
||
|
|
||
|
.. kernel-doc:: include/linux/list.h
|
||
|
:internal:
|