Linked List : list_is_last ========================== .. tab-set:: .. tab-item:: Linked List : list_is_last * In this program, you are going to learn .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * How to test whether a list is the last entry in list ? .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * How to use the below API's ? * `INIT_LIST_HEAD `_ * `list_add `_ * `list_add_tail `_ * `list_last_entry `_ * `list_is_last `_ * `list_for_each_entry `_ * `list_for_each_entry_safe `_ * `list_del `_ .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow Topics in this section, * :ref:`Explanation of Program part by part ` * :ref:`List of headers ` * :ref:`Modules macro ` * :ref:`Initialize function and variables ` * :ref:`Module init function ` * :ref:`Module exit function ` * :ref:`Linked list APIs ` * :ref:`Mention init and exit function ` * :ref:`See the full program below ` * :ref:`Makefile ` * :ref:`Compile and Load ` * :ref:`Summary of Linked List APIs ` .. _list_is_last_4: .. tab-set:: .. tab-item:: Explanation of program part by part * In this example, we are going to test whether a list is the first entry in list. .. _list_is_last_5: .. tab-set:: .. tab-item:: List of headers * Add the list of header files to refer the APIs used in this program. .. code-block:: c #include #include #include #include #include .. _list_is_last_6: .. tab-set:: .. tab-item:: Modules macro * Add the modules macro which lists the information about the license, author and description. .. code-block:: c MODULE_LICENSE("GPL"); MODULE_AUTHOR("linux_usr"); MODULE_DESCRIPTION("Linked List"); .. _list_is_last_7: .. tab-set:: .. tab-item:: Initialize function and variables * ``list_head`` is used to initialize the list. .. code-block:: c static struct list_head my_list; * ``INIT_LIST_HEAD`` is used to initialize a list_head structure. .. code-block:: c INIT_LIST_HEAD(&my_list); INIT_LIST_HEAD(&new_node->list); .. _list_is_last_8: .. tab-set:: .. tab-item:: Module init function * Add the module init function to execute the function once when the module is loaded to the linux kernel. .. code-block:: c static int __init linkedlist_init(void) { struct list_node *entry; pr_info("Driver loaded\n"); INIT_LIST_HEAD(&my_list); insert_func(2); display(); last_entry = list_last_entry(&my_list, struct list_node, list); pr_info("The last entry has value : %d\n", last_entry->data); if (list_is_last(&last_entry->list, &my_list)) pr_info("The first entry is the last entry!\n"); return 0; } * ``list_last_entry`` will give the last entry of the list. .. code-block:: c last_entry = list_last_entry(&my_list, struct list_node, list); * ``list_is_last`` tests whether a list is the last entry in list. .. code-block:: c list_is_last(&last_entry->list, &my_list); .. _list_is_last_9: .. tab-set:: .. tab-item:: Module exit function * Add module exit function which is executed once the module is unloaded from the kernel. .. code-block:: c static void __exit linkedlist_exit(void) { struct list_node *ptr, *next; list_for_each_entry_safe(ptr, next, &my_list, list) { list_del(&ptr->list); kfree(ptr); } pr_info("Driver unloaded\n"); } .. _list_is_last_10: .. tab-set:: .. tab-item:: Linked List APIs * ``insert_rear`` function inserts a new node at the end with the given ``value`` into the linked list. .. code-block:: c void insert_rear(int value) { struct list_node * new_node; new_node = kmalloc(sizeof(struct list_node), GFP_KERNEL); if (!new_node) { pr_err("Memory allocation failed\n"); return; } new_node->data = value; INIT_LIST_HEAD(&new_node->list); list_add_tail(&new_node->list, &my_list); } * ``display`` function iterates through the linked list using ``list_for_each_entry``. It prints the data in each node to the kernel log. .. code-block:: c void display(void) { struct list_node * ptr; pr_info("Linked list: "); list_for_each_entry(ptr, &my_list, list) { printk(KERN_CONT "%d -> ", ptr->data); } printk(KERN_CONT "NULL\n"); } .. _list_is_last_11: .. tab-set:: .. tab-item:: Mention init and exit functions * Add the module init and exit which is called when the module is loaded and unloaded. .. code-block:: c module_init(linkedlist_init); module_exit(linkedlist_exit); .. _list_is_last_0: .. tab-set:: .. tab-item:: See the full program below .. tab-set:: .. tab-item:: linked_list.c .. literalinclude:: list_is_last/linked_list.c :language: c :linenos: .. _list_is_last_1: .. tab-set:: .. tab-item:: Makefile .. literalinclude:: list_is_last/Makefile :language: c :linenos: .. _list_is_last_2: .. tab-set:: .. tab-item:: Compile and Load * Run Make to compile the module. .. code-block:: shell $make make -C /lib/modules/5.4.0-150-generic/build M=$HOME/kernel_linked_list modules make[1]: Entering directory '/usr/src/linux-headers-5.4.0-150-generic' CC [M] $HOME/kernel_linked_list/linked_list.o Building modules, stage 2. MODPOST 1 modules CC [M] $HOME/kernel_linked_list/linked_list.mod.o LD [M] $HOME/kernel_linked_list/linked_list.ko make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-150-generic' * Run ls to check if linked_list.ko is generated or not. .. code-block:: shell $ ls -l total 36 -rw-rw-r-- 1 test test 154 Feb 26 13:18 Makefile -rw-rw-r-- 1 test test 47 Feb 26 13:18 modules.order -rw-rw-r-- 1 test test 0 Feb 26 13:18 Module.symvers -rw-rw-r-- 1 test test 820 Feb 26 13:18 linked_list.c -rw-rw-r-- 1 test test 5880 Feb 26 13:18 linked_list.ko -rw-rw-r-- 1 test test 47 Feb 26 13:18 linked_list.mod -rw-rw-r-- 1 test test 919 Feb 26 13:18 linked_list.mod.c -rw-rw-r-- 1 test test 3448 Feb 26 13:18 linked_list.mod.o -rw-rw-r-- 1 test test 3320 Feb 26 13:18 linked_list.o * Run insmod to load the module. .. code-block:: shell $ sudo insmod ./linked_list.ko * Check the kernel messages to see if the kernel module is loaded or not. .. code-block:: shell $ dmesg [ 6502.274246] Driver loaded [ 6502.274247] Linked list: 2 -> NULL [ 6502.274249] The last entry has value : 2 [ 6502.274249] The first entry is the last entry! * Run rmmod to unload the module. .. code-block:: shell $ sudo rmmod linked_list * Check dmesg to see if the module is unloaded from kernel. .. code-block:: shell $ dmesg [ 6502.274246] Driver loaded [ 6502.274247] Linked list: 2 -> NULL [ 6502.274249] The last entry has value : 2 [ 6502.274249] The first entry is the last entry! [ 6506.537914] Driver unloaded .. _list_is_last_3: .. tab-set:: .. tab-item:: Summary =============================== ===================================================================== API Learning =============================== ===================================================================== INIT_LIST_HEAD To initialize a list_head structure LIST_HEAD To initialize the list list_for_each_entry To iterate over list of given type list_add To insert a new entry after the specified head list_add_tail To insert a new entry before the specified head list_last_entry To retrieve the last list entry list_is_last To test whether a list is the last entry in list list_for_each_entry_safe To iterate over list of given type safe against removal of list entry list_del To delete entry from list =============================== ===================================================================== .. card:: See Also * Previous Chapters * :doc:`../chapter1_basics/chapter1_basics` * :doc:`../chapter2_kthreads/chapter2_kthreads` * :doc:`../chapter3_tasklets/chapter3_tasklets` * :doc:`../chapter4_workqueue/chapter4_workqueue` * :doc:`../chapter5_timer/chapter5_timer` * Other Linked List topics * :doc:`insert_rear` * :doc:`insert_at_pos` * :doc:`delete_rear` * :doc:`delete_front` * :doc:`delete_at_pos` * :doc:`list_splice` * :doc:`list_splice_init` * :doc:`list_splice_tail` * :doc:`list_splice_tail_init` * :doc:`list_cut_position` * :doc:`list_del_init` * :doc:`list_first` * :doc:`list_first_entry_or_null` * :doc:`list_for_each` * :doc:`list_for_each_entry_continue` * :doc:`list_for_each_entry_continue_reverse` * :doc:`list_for_each_entry_safe_reverse` * :doc:`list_is_singular` * :doc:`list_last` * :doc:`list_move` * :doc:`list_move_tail` * :doc:`list_replace` * :doc:`list_replace_init` * Next Chapter * :doc:`../chapter9_fileSystem/chapter9_fileSystem` * Other Chapter * :doc:`../chapter10_netlink/chapter10_netlink`