Adding delayed work to kthread worker ====================================== .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow Topics in this section, * :ref:`Version Info ` * :ref:`Learnings in this section ` * :ref:`Explanation of kthread APIs ` * :ref:`kthread_create_worker ` * :ref:`kthread_run ` * :ref:`kthread_init_delayed_work ` * :ref:`kthread_queue_delayed_work ` * :ref:`kthread_cancel_delayed_work_sync ` * :ref:`kthread_mod_delayed_work ` * :ref:`kthread_destroy_worker ` * :ref:`kthread_should_stop ` * :ref:`Explanation of miscellaneous APIs ` * :ref:`Module parameter APIs ` * :ref:`IS_ERR ` * :ref:`container_of ` * :ref:`kmalloc ` * :ref:`pr_info ` * :ref:`wake_up_process ` * :ref:`msleep ` * :ref:`msecs_to_jiffies ` * :ref:`Driver entry point APIs ` * :ref:`Example 1: Create kthread_delayed_work using kthread_init_delayed_work ` * :ref:`List of headers ` * :ref:`Module Macros ` * :ref:`Initialize thread variables ` * :ref:`Module init function ` * :ref:`Thread start function ` * :ref:`Module exit function ` * :ref:`Thread stop function ` * :ref:`Thread function API ` * :ref:`Work function API ` * :ref:`Driver entry points ` * :ref:`See the full program below ` * :ref:`Makefile ` * :ref:`Compile and Load the module ` * :ref:`Example 2: Cancel a kthread_delayed_work using kthread_cancel_delayed_work_sync ` * :ref:`List of headers ` * :ref:`Module Macros ` * :ref:`Initialize thread variables ` * :ref:`Module init function ` * :ref:`thread start function ` * :ref:`Module exit function ` * :ref:`thread stop function ` * :ref:`Thread function API ` * :ref:`Work function ` * :ref:`Driver entry points ` * :ref:`See the full program below ` * :ref:`Makefile ` * :ref:`Compile and Load the module ` * :ref:`Example 3: Modify queue delay of work using kthread_mod_delayed_work ` * :ref:`List of headers ` * :ref:`Module Macros ` * :ref:`Initialize thread variables ` * :ref:`Module init function ` * :ref:`Thread start function ` * :ref:`Module exit function ` * :ref:`Thread stop function ` * :ref:`Thread function API ` * :ref:`Work function ` * :ref:`Driver entry points ` * :ref:`See the full program below ` * :ref:`Makefile ` * :ref:`Compile and Load the module ` * :ref:`Example 4: Queue multiple delayed works to kthread_worker ` * :ref:`List of headers ` * :ref:`Module Macros ` * :ref:`Initialize thread variables ` * :ref:`Module init function ` * :ref:`Thread start function ` * :ref:`Module exit function ` * :ref:`Thread stop function ` * :ref:`Thread function API ` * :ref:`Work function ` * :ref:`Driver entry points ` * :ref:`See the full program below ` * :ref:`Makefile ` * :ref:`Compile and Load the module ` * :ref:`Summary of Kthread APIs ` * :ref:`Summary of Miscellaneous APIs ` .. _p5_delayedkthreadworker_0: .. tab-set:: .. tab-item:: Version Info =============================== ======================================= # Version =============================== ======================================= Ubuntu Ubuntu 22.10 Kernel 6.7.9 =============================== ======================================= .. _p5_delayedkthreadworker_1: .. tab-set:: .. tab-item:: Learnings in this section * In this program, you are going to learn .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * How to create the delayed kthread work ? .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * How to add delayed kthread work to kthread worker? .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * How to destroy the kthread worker ? .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * How to use Kthread APIs ? * `kthread_create_worker `_ * `kthread_init_delayed_work `_ * `kthread_queue_delayed_work `_ * `kthread_run `_ * `kthread_cancel_delayed_work_sync `_ * `kthread_mod_delayed_work `_ * `kthread_destroy_worker `_ * `kthread_should_stop `_ .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * How to use below APIs ? * `MODULE_LICENSE `_ * `MODULE_DESCRIPTION `_ * `MODULE_AUTHOR `_ * `IS_ERR `_ * `container_of `_ * `kmalloc `_ * `pr_info `_ * `wake_up_process `_ * `msleep `_ * `msecs_to_jiffies `_ * `module_init `_ * `module_exit `_ .. _p5_delayedkthreadworker_2: .. tab-set:: .. tab-item:: Explanation of Kthread APIs .. _p5_delayedkthreadworker_3: .. tab-set:: .. tab-item:: kthread_create_worker * Here is the function prototype of the API: `kthread_create_worker `_ .. code-block:: c #include struct kthread_worker *kthread_create_worker(unsigned int flags, const char namefmt[], ...); * where * `kthread_create_worker `_: creates a kthread worker. * return type: * returns a pointer (i.e struct kthread_worker*) to the allocated worker on success * ERR_PTR(-ENOMEM) when the needed structures could not get allocated * ERR_PTR(-EINTR) when the caller was killed by a fatal signal. * flags: flags modifying the default behaviour of the kthread worker. * namefmt: printf-style name for the kthread worker. * Here is an example of how to use the API, .. code-block:: c kthread_create_worker(0,"sample kthread worker"); .. _p5_delayedkthreadworker_5: .. tab-set:: .. tab-item:: kthread_run * Here is the function prototype of the API: `kthread_run `_ .. code-block:: c #include #define kthread_run(threadfn, data, namefmt, ...) * where * `kthread_run `_ : is used to create and wake a kthread * return type: struct task_struct* (i.e) address of the kthread * threadfn: function to executed by kthread * data: data pointer for threadfn which can be used to send any possible arguments required for threadfn. * namefmt: printf-style format for the thread name which will be displayed on ps output when the thread is in execution. * Here is an example of how to use the API, .. code-block:: c kthread_run(mythread,NULL,"sample kthread"); .. _p5_delayedkthreadworker_6: .. tab-set:: .. tab-item:: kthread_init_delayed_work * Here is the prototype of the API: `kthread_init_delayed_work `_ .. code-block:: c #include #define kthread_init_delayed_work(dwork, fn) \ do { \ kthread_init_work(&(dwork)->work, (fn)); \ timer_setup(&(dwork)->timer, \ kthread_delayed_work_timer_fn, \ TIMER_IRQSAFE); \ } while (0) * where * `kthread_init_delayed_work `_ : used to initialize a delayed work. * work: kthread work which needs to be initialized * fn: function which is needs to be executed once kthread work is created. * Here is an example of how to use the API, .. code-block:: c kthread_init_delayed_work(mydelayedwork,mydelayedworkfn); .. _p5_delayedkthreadworker_57: .. tab-set:: .. tab-item:: kthread_queue_delayed_work * Here is the prototype of the API: `kthread_queue_delayed_work `_ .. code-block:: c #include bool kthread_queue_delayed_work(struct kthread_worker *worker,struct kthread_delayed_work *dwork,unsigned long delay); * where * `kthread_queue_delayed_work `_ : queue the associated kthread work after delay * worker: target kthread_worker * dwork: kthread_delayed_work to queue * delay: number of jiffies to wait before queuing. * return type: returns type if it is successfully queue to kthread_worker, false if its already pending * Here is an example of how to use the API, .. code-block:: c kthread_queue_delayed_work(myworker,mywork); .. _p5_delayedkthreadworker_62: .. tab-set:: .. tab-item:: kthread_cancel_delayed_work_sync * Here is the prototype of the API: `kthread_cancel_delayed_work_sync `_ .. code-block:: c #include bool kthread_cancel_delayed_work_sync(struct kthread_delayed_work *work); * where * `kthread_cancel_delayed_work_sync `_ : cancel a kthread_delayed_work and wait for it to finish * work: the kthread_delayed_work to cancel. * return type: true if work is pending , false otherwise. * Here is an example of how to use the API, .. code-block:: c kthread_cancel_delayed_work_sync(mywork); .. _p5_delayedkthreadworker_81: .. tab-set:: .. tab-item:: kthread_mod_delayed_work * Here is the prototype of the API: `kthread_mod_delayed_work `_ .. code-block:: c # include bool kthread_mod_delayed_work(struct kthread_worker *worker, struct kthread_delayed_work *dwork, unsigned long delay); * where * `kthread_mod_delayed_work `_ : modify delay of kthread delayed work * worker: kthread worker to use * dwork: delayed work to queue * delay: number of jiffies to wait before queuing * return type: return false if dwork is queued or idle, true otherwise. * Here is an example of how to use the API, .. code-block:: c kthread_mod_delayed_work(myworker,mywork,msecs_to_jiffies(10)); .. _p5_delayedkthreadworker_7: .. tab-set:: .. tab-item:: kthread_destroy_worker * Here is the prototye of the API: `kthread_destroy_worker `_ .. code-block:: c #include void kthread_destroy_worker(struct kthread_worker *worker); * where * `kthread_destroy_worker `_ : flush and destroy the kthread worker. * worker: worker which needs to be destroyed. .. _p5_delayedkthreadworker_65: .. tab-set:: .. tab-item:: kthread_should_stop * Here is the function prototype of the API: `kthread_should_stop `_ .. code-block:: c #include bool kthread_should_stop(void); * where * `kthread_should_stop `_: this is used to determine whether the thread should return now Whenever the `kthread_stop() `_ is called it will be woken and returns true. * return type: returns true when the thread is stopped, false when the thread is still in execution * Here is an example of how to use the API, .. code-block:: c while (!kthread_should_stop()) { //add the instructions to be performed during thread execution. } .. _p5_delayedkthreadworker_8: .. tab-set:: .. tab-item:: Explanation of miscellaneous APIs .. _p5_delayedkthreadworker_9: .. tab-set:: .. tab-item:: Module parameter APIs * Here is the prototype of module paramter APIs .. code-block:: c #include #define MODULE_LICENSE(_license) MODULE_FILE MODULE_INFO(license, _license) #define MODULE_AUTHOR(_author) MODULE_INFO(author, _author) #define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description) * where * `MODULE_LICENSE `_: tells the kernel what license is used by our module. * `MODULE_AUTHOR `_: denotes the author of this kernel module. * `MODULE_DESCRIPTION `_: gives a basic idea about what the kernel module does. * These information can be found when modinfo command is used which lists out all these above mentioned information. * Here is the example of how to use the Module parameter APIs, .. code-block:: c MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linux Usr"); MODULE_DESCRIPTION("Sample kernel module"); .. _p5_delayedkthreadworker_10: .. tab-set:: .. tab-item:: IS_ERR * Here is the prototype of the API: `IS_ERR `_ .. code-block:: c #include static inline bool __must_check IS_ERR(__force const void *ptr); * where * `IS_ERR `_: Detects an error pointer * return type: return true if it's an error pointer else return false. * ptr: pointer which needs to detected. * Here is an example of how to use the API, .. code-block:: c if(IS_ERR(sample_ptr)) { //instructions to be executed when error ptr is detected } else { //instructions to be executed when error ptr is not detected } .. _p5_delayedkthreadworker_58: .. tab-set:: .. tab-item:: cointainer_of * Here is the prototype of API: `container_of `_ .. code-block:: c #include #define container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member) * __mptr = (ptr); \ (type *)((char *)__mptr - offsetof(type, member)); }) #endif * where * `container_of `_ : cast a member of the structure to the containing structure. * ptr: the pointer to the member * type: the type of container struct this is embedded in * member: the name of the member within the struct * Here is an example of how to use the API, .. code-block:: c container_of(myptr,struct mysamplestruct,samplemember); .. _p5_delayedkthreadworker_59: .. tab-set:: .. tab-item:: kmalloc * Here is the prototype of the API: `kmalloc `_ .. code-block:: c #include void *kmalloc(size_t size, gfp_t gfp); * where * kmalloc: allocate kernel memory * size: how many bytes of memory is required * flags: describle the allocation context * Here is an example of how to use the API, .. code-block:: c kmalloc(sizeof(struct mystruct),GFP_KERNEL); .. _p5_delayedkthreadworker_11: .. tab-set:: .. tab-item:: pr_info * Here is the prototype of the API: `pr_info `_ .. code-block:: c #include #define pr_info(fmt, ...) \ printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__) * where * `pr_info `_: Prints an info-level messages * fmt: format string * Here is an example of how to use the API, .. code-block:: c pr_info("//sample print statement"); .. _p5_delayedkthreadworker_12: .. tab-set:: .. tab-item:: wake_up_process * Here is the example of the API: `wake_up_process `_ .. code-block:: c #include extern int wake_up_process(struct task_struct *tsk); * where * `wake_up_process `_: wake up a specific process * return type: returns 1 if the process is woken up, 0 if the process is in running state. * tsk: process to be woken up. * Here is the example of how to use the API, .. code-block:: c wake_up_process(mythread); .. _p5_delayedkthreadworker_66: .. tab-set:: .. tab-item:: msecs_to_jiffies * Here is the prototype of the API: `msecs_to_jiffies `_ .. code-block:: c #include static __always_inline unsigned long msecs_to_jiffies(const unsigned int m); * where * `msecs_to_jiffies `_ : convert milliseconds to jiffies * m: time in milliseconds * return type: returns jiffies values .. _p5_delayedkthreadworker_13: .. tab-set:: .. tab-item:: msleep * Here is the example of the API: `msleep `_ .. code-block:: c #include void msleep(unsigned int msecs); * where * `msleep `_: will put it in sleep for a certain amount of msecs time. * msecs: time in milliseconds to sleep for * Here is the example of how to use the API, .. code-block:: c msleep(1000); .. _p5_delayedkthreadworker_14: .. tab-set:: .. tab-item:: Driver entry point API's * Here is the prototype of the Driver entry point API's .. code-block:: c #include #define module_init(x) __initcall(x); #define module_exit(x) __exitcall(x); * where * `module_init `_: driver initialization entry point which will be called at module insertion time. * `module_exit `_: driver exit entry point which will be called during the removal of module. * x: * function to be run at module insertion for `module_init `_ function. * function to be run when driver is removed for `module_exit `_ function. * Here is an example of how to use the driver entry point API's .. code-block:: c module_init(myinitmodule); module_exit(myexitmodule); .. _p5_delayedkthreadworker_15: .. tab-set:: .. tab-item:: Example 1: Create kthread_delayed_work using kthread_init_delayed_work * In this example let's see how to create kthread delayed work using kthread_init_delayed_work and execute it. .. _p5_delayedkthreadworker_16: .. tab-set:: .. tab-item:: List of headers * Include the follow header files(.h) to refer the API being used for the execution. .. code-block:: c #include #include #include #include #include #include #include .. _p5_delayedkthreadworker_17: .. tab-set:: .. tab-item:: Module macros * Add the following module macros to display information about the license, author and description about the module. .. code-block:: c MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linux Usr"); MODULE_DESCRIPTION("Example of kthread_init_delayed_work"); .. _p5_delayedkthreadworker_18: .. tab-set:: .. tab-item:: Initialize thread variables * Declare the thread variables which we are going to create and use in this example .. code-block:: c bool ret_val; static struct task_struct *my_thread; static struct kthread_worker *worker; struct my_work { struct kthread_delayed_work my_kthread_delayed_work; int i; }; .. _p5_delayedkthreadworker_19: .. tab-set:: .. tab-item:: Module init function * Add the module init function which will be executed once we load the kernel module using insmod command. .. code-block:: c static int __init kthread_init_delayed_work_init(void) { pr_info("Inside kthread init function\n"); thread_start(); return 0; } .. _p5_delayedkthreadworker_51: .. tab-set:: .. tab-item:: thread start function * Add the thread start function which creates kthread, on success creation it starts executing the task. .. code-block:: c void thread_start(void) { my_thread = kthread_run(def_thread_fun,NULL,"kthread_init_delayed_work_init thread example"); if(IS_ERR(my_thread)) pr_info("Error creating thread\n"); else pr_info("Created kthread\n"); } .. _p5_delayedkthreadworker_20: .. tab-set:: .. tab-item:: Module exit function * Add the module exit function which will be executed once we unload the kernel module using rmmod command. .. code-block:: c static void __exit kthread_init_delayed_work_exit(void) { pr_info("Inside kthread exit function\n"); thread_stop(); } .. _p5_delayedkthreadworker_52: .. tab-set:: .. tab-item:: Thread stop function * Add the thread stop function which destroys the thread and stops the execution. .. code-block:: c void thread_stop(void) { if(my_thread) { kthread_stop(my_thread); kthread_destroy_worker(worker); pr_info("Destroyed kthread and worker"); } } .. _p5_delayedkthreadworker_21: .. tab-set:: .. tab-item:: Thread function API * Add the thread function API which will be called as soon as the kthread is created and is in running state. .. code-block:: c int def_thread_fun(void *data) { struct my_work my_def_work; kthread_init_delayed_work(&my_def_work.my_kthread_delayed_work,def_delayed_work_function); pr_info("Initializing kthread work\n"); worker = kthread_create_worker(0,"kthread_init_delayed_work_init worker example"); if (IS_ERR(worker)) pr_info("Error creating worker\n"); else pr_info("Created kthread worker\n"); ret_val = kthread_queue_delayed_work(worker,&my_def_work.my_kthread_delayed_work,msecs_to_jiffies(10)); if (ret_val) pr_info("Queue the work to worker\n"); else pr_info("queue is pending\n"); while (!kthread_should_stop()) { pr_info("thread_execution\n"); msleep(100); } return 0; } .. _p5_delayedkthreadworker_60: .. tab-set:: .. tab-item:: Work function API * Add the work function which is executed once the work is queued to kthread_worker. .. code-block:: c void def_delayed_work_function(struct kthread_work *work) { struct my_work *my_data; my_data = kmalloc(sizeof(struct my_work*),GFP_KERNEL); pr_info("Inside work function\n"); my_data->i = 0; while (my_data->i <= 10) { pr_info("my_data->i = %d\n",my_data->i); my_data->i++; } } .. _p5_delayedkthreadworker_22: .. tab-set:: .. tab-item:: Driver entry points * Add the driver entry points which will be executed once the module is inserted or removed from the kernel. .. code-block:: c module_init(kthread_init_delayed_work_init); module_exit(kthread_init_delayed_work_exit); .. _p5_delayedkthreadworker_23: .. tab-set:: .. tab-item:: See the full program below .. tab-set:: .. tab-item:: kthread.c .. literalinclude:: p5_delayedkthreadworker/kthread_init_delayed_work/kthread.c :language: c :linenos: .. _p5_delayedkthreadworker_24: .. tab-set:: .. tab-item:: Makefile .. literalinclude:: p5_delayedkthreadworker/kthread_init_delayed_work/Makefile :language: c :linenos: .. _p5_delayedkthreadworker_25: .. tab-set:: .. tab-item:: Compile and load the module * Run make to compile the kernel source and generate the .ko image. .. code-block:: shell make -C /lib/modules/6.7.9/build M=$HOME/kthread_examples/ make[1]: Entering directory '/usr/src/linux-headers-6.7.9' warning: the compiler differs from the one used to build the kernel The kernel was built by: x86_64-linux-gnu-gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0 You are using: gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0 CC [M] $HOME/kthread_examples/kthread.o MODPOST $HOME/kthread_examples/Module.symvers CC [M] $HOME/kthread_examples/kthread.mod.o LD [M] $HOME/kthread_examples/kthread.ko BTF [M] $HOME/kthread_examples/kthread.ko Skipping BTF generation for $HOME/kthread_examples/kthread.ko due to unavailability of vmlinux make[1]: Leaving directory '/usr/src/linux-headers-6.7.9' * Check if the .ko is generated or not using ls command. .. code-block:: shell test@test-V520-15IKL:~$ ls -l total 360 -rw-rw-r-- 1 test test 713 Mar 18 16:06 kthread.c -rw-rw-r-- 1 test test 169784 Mar 18 16:08 kthread.ko -rw-rw-r-- 1 test test 58 Mar 18 16:08 kthread.mod -rw-rw-r-- 1 test test 1047 Mar 18 16:08 kthread.mod.c -rw-rw-r-- 1 test test 96512 Mar 18 16:08 kthread.mod.o -rw-rw-r-- 1 test test 74696 Mar 18 16:08 kthread.o -rw-rw-r-- 1 test test 161 Mar 18 16:00 Makefile -rw-rw-r-- 1 test test 58 Mar 18 16:08 modules.order -rw-rw-r-- 1 test test 0 Mar 18 16:08 Module.symvers * Run modinfo command to get the information about the kernel module. .. code-block:: shell test@test-V520-15IKL:~/.../tc_1$ modinfo kthread.ko filename: $HOME/kthread_examples/kthread.ko description: Example of kthread_init_delayed_work author: Linux Usr license: GPL srcversion: 8D2147F67AB01CF0E482DAC depends: retpoline: Y name: kthread vermagic: 6.7.9 SMP preempt mod_unload modversions * insert the module using insmod command. .. code-block:: shell test@test-V520-15IKL:~$ sudo insmod ./kthread.ko * check if the module is loaded or not using lsmod command. .. code-block:: shell test@test-V520-15IKL:~$ sudo lsmod | grep kthread kthread 16384 0 * check if the thread is created or not using ps command. .. code-block:: shell test@test-V520-15IKL:~$ ps -N | grep kthread_init_delayed_work 11404 ? 00:00:00 kthread_init_delayed_work_init thread example 11405 ? 00:00:00 kthread_init_delayed_work_init worker example * check for the kernel messages from init function and thread function once the module is loaded and thread is created. .. code-block:: shell test@test-V520-15IKL:~$ sudo dmesg [11715.486700] Inside kthread_init function [11715.486727] Created kthread [11715.486728] Initializing kthread work [11715.486743] Created kthread worker [11715.486744] Queue the work to worker [11715.486744] thread_execution [11715.499090] Inside work function [11715.499091] my_data->i = 0 [11715.591078] thread_execution [11715.607082] my_data->i = 1 [11715.698965] thread_execution [11715.715088] my_data->i = 2 * remove the module from kernel using rmmod command. .. code-block:: shell test@test-V520-15IKL:~$ sudo rmmod kthread * check if the module is still loaded after removing the kernel module using lsmod if it is not displayed in lsmod output it is verified that the module is removed successfully. .. code-block:: shell test@test-V520-15IKL:~$ sudo lsmod | grep kthread test@test-V520-15IKL:~$ * check if the thread is destroyed using ps command if it is not displayed in ps output we can confirm that the thread is destroyed successfully. .. code-block:: shell test@test-V520-15IKL:~$ ps -N | grep kthread_init_work test@test-V520-15IKL:~$ * Check for kernel messages from exit function using dmesg command. .. code-block:: shell test@test-V520-15IKL:~$ sudo dmesg [11723.785020] Inside kthread exit function [11723.811440] Destroyed kthread and worker .. _p5_delayedkthreadworker_26: .. tab-set:: .. tab-item:: Example 2: Cancel kthread_delayed_work using kthread_cancel_delayed_work_sync * In this example let's see how to cancel kthread_delayed_work using kthread_cancel_delayed_work_sync. .. _p5_delayedkthreadworker_27: .. tab-set:: .. tab-item:: List of headers * Include the follow header files(.h) to refer the API being used for the execution. .. code-block:: c #include #include #include #include #include #include #include .. _p5_delayedkthreadworker_28: .. tab-set:: .. tab-item:: Module macros * Add the following module macros to display information about the license, author and description about the module. .. code-block:: c MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linux Usr"); MODULE_DESCRIPTION("Example of kthread_cancel_delayed_work_sync"); .. _p5_delayedkthreadworker_29: .. tab-set:: .. tab-item:: Initialize thread variables * Declare the thread variables which we are going to create and use in this example .. code-block:: c bool ret_val; static struct task_struct *my_thread; static struct kthread_worker *worker; struct my_work { struct kthread_delayed_work my_kthread_delayed_work; int i; }; .. _p5_delayedkthreadworker_30: .. tab-set:: .. tab-item:: Module init function * Add the module init function which will be executed once we load the kernel module using insmod command. .. code-block:: c static int __init kthread_cancel_delayed_work_sync_init(void) { pr_info("Inside kthread init function\n"); thread_start(); return 0; } .. _p5_delayedkthreadworker_53: .. tab-set:: .. tab-item:: Thread start function * Add the thread start function in which the worker and thread is created and starts its execution. .. code-block:: c void thread_start(void) { my_thread = kthread_run(def_thread_fun,NULL,"kthread_cancel_work_sync thread example"); if(IS_ERR(my_thread)) pr_info("Error creating kthread\n"); else pr_info("Created kthread\n"); } .. _p5_delayedkthreadworker_31: .. tab-set:: .. tab-item:: Module exit function * Add the module exit function which will be executed once we unload the kernel module using rmmod command. .. code-block:: c static void __exit kthread_cancel_delayed_work_sync_exit(void) { pr_info("Inside kthread exit function\n"); thread_stop(); } .. _p5_delayedkthreadworker_54: .. tab-set:: .. tab-item:: Thread stop function * Add the thread stop function in which worker is destroyed and the thread stops its execution. .. code-block:: c void thread_stop(void) { if(my_thread) { kthread_stop(my_thread); kthread_destroy_worker(worker); pr_info("Destroyed kthread and worker"); } } .. _p5_delayedkthreadworker_32: .. tab-set:: .. tab-item:: Thread function API * Add the thread function API which will be called as soon as the kthread is created and is in running state. .. code-block:: c int def_thread_fun(void *data) { struct my_work my_def_work; kthread_init_work(&my_def_work.my_kthread_work,def_work_function); pr_info("Initializing kthread work\n"); worker = kthread_create_worker(0,"kthread_cancel_work_sync worker example"); if (IS_ERR(worker)) pr_info("Error creating worker\n"); else pr_info("Created kthread worker\n"); ret_val = kthread_queue_delayed_work(worker,&my_def_work.my_kthread_delayed_work,msecs_to_jiffies(10)); if (ret_val) pr_info("Queue the work to worker\n"); else pr_info("Work is in pending state"); while (!kthread_should_stop()) { pr_info("thread execution\n"); msleep(1000); kthread_cancel_delayed_work_sync(&my_def_work.my_kthread_delayed_work); msleep(100); } pr_info("Cancel the kthread delayed work\n"); return 0; } .. _p5_delayedkthreadworker_61: .. tab-set:: .. tab-item:: Work function * Add the work function which will be executed once kthread_work is queued to kthread_worker. .. code-block:: c void def_work_function(struct kthread_work *work) { struct my_work *my_data; my_data = kmalloc(sizeof(struct my_work*),GFP_KERNEL); pr_info("Inside work function\n"); my_data->i = 0; while (my_data->i <= 10) { pr_info("my_data->i = %d\n",my_data->i); my_data->i++; msleep(100); } } .. _p5_delayedkthreadworker_33: .. tab-set:: .. tab-item:: Driver entry points * Add the driver entry points which will be executed once the module is inserted or removed from the kernel. .. code-block:: c module_init(kthread_cancel_delayed_work_sync_init); module_exit(kthread_cancel_delayed_work_sync_exit); .. _p5_delayedkthreadworker_34: .. tab-set:: .. tab-item:: See the full program below .. tab-set:: .. tab-item:: kthread.c .. literalinclude:: p5_delayedkthreadworker/kthread_cancel_delayed_work_sync/kthread.c :language: c :linenos: .. _p5_delayedkthreadworker_35: .. tab-set:: .. tab-item:: Makefile .. literalinclude:: p5_delayedkthreadworker/kthread_cancel_delayed_work_sync/Makefile :language: c :linenos: .. _p5_delayedkthreadworker_36: .. tab-set:: .. tab-item:: Compile and load the module * Run make to compile the kernel source and generate the .ko image. .. code-block:: shell make -C /lib/modules/6.7.9/build M=$HOME/kthread_examples/ make[1]: Entering directory '/usr/src/linux-headers-6.7.9' warning: the compiler differs from the one used to build the kernel The kernel was built by: x86_64-linux-gnu-gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0 You are using: gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0 CC [M] $HOME/kthread_examples/kthread.o MODPOST $HOME/kthread_examples/Module.symvers CC [M] $HOME/kthread_examples/kthread.mod.o LD [M] $HOME/kthread_examples/kthread.ko BTF [M] $HOME/kthread_examples/kthread.ko Skipping BTF generation for $HOME/kthread_examples/kthread.ko due to unavailability of vmlinux make[1]: Leaving directory '/usr/src/linux-headers-6.7.9' * Check if the .ko is generated or not using ls command. .. code-block:: shell test@test-V520-15IKL:~$ ls -l total 360 -rw-rw-r-- 1 test test 713 Mar 18 16:06 kthread.c -rw-rw-r-- 1 test test 169784 Mar 18 16:08 kthread.ko -rw-rw-r-- 1 test test 58 Mar 18 16:08 kthread.mod -rw-rw-r-- 1 test test 1047 Mar 18 16:08 kthread.mod.c -rw-rw-r-- 1 test test 96512 Mar 18 16:08 kthread.mod.o -rw-rw-r-- 1 test test 74696 Mar 18 16:08 kthread.o -rw-rw-r-- 1 test test 161 Mar 18 16:00 Makefile -rw-rw-r-- 1 test test 58 Mar 18 16:08 modules.order -rw-rw-r-- 1 test test 0 Mar 18 16:08 Module.symvers * Run modinfo command to get the information about the kernel module. .. code-block:: shell test@test-V520-15IKL:~/.../tc_1$ modinfo kthread.ko filename: $HOME/kthread_examples/kthread.ko description: Example of kthread_cancel_delayed_work_sync author: Linux Usr license: GPL srcversion: 8D2147F67AB01CF0E482DAC depends: retpoline: Y name: kthread vermagic: 6.7.9 SMP preempt mod_unload modversions * insert the module using insmod command. .. code-block:: shell test@test-V520-15IKL:~$ sudo insmod ./kthread.ko * check if the module is loaded or not using lsmod command. .. code-block:: shell test@test-V520-15IKL:~$ sudo lsmod | grep kthread kthread 16384 0 * check if the thread is created or not using ps command. .. code-block:: shell test@test-V520-15IKL:~$ ps -N | grep kthread_cancel_delayed_work_sync 14117 ? 00:00:00 kthread_cancel_delayed_work_sync thread example 14118 ? 00:00:00 kthread_cancel_delayed_work_sync worker example * check for the kernel messages from init function and thread function once the module is loaded and thread is created. .. code-block:: shell test@test-V520-15IKL:~$ sudo dmesg [14116.036297] Inside kthread_init function [14116.036322] Created kthread [14116.036324] Initializing kthread work [14116.036371] Creating kthread worker [14116.036373] Queue the work to worker [14116.036373] thread execution [14116.051054] Inside work function [14116.051060] my_data->i = 0 [14116.159099] my_data->i = 1 [14116.267063] my_data->i = 2 * remove the module from kernel using rmmod command. .. code-block:: shell test@test-V520-15IKL:~$ sudo rmmod kthread * check if the module is still loaded after removing the kernel module using lsmod if it is not displayed in lsmod output it is verified that the module is removed successfully. .. code-block:: shell test@test-V520-15IKL:~$ sudo lsmod | grep kthread test@test-V520-15IKL:~$ * check if the thread is destroyed using ps command if it is not displayed in ps output we can confirm that the thread is destroyed successfully. .. code-block:: shell test@test-V520-15IKL:~$ ps -N | grep kthread_cancel_work_sync test@test-V520-15IKL:~$ * Check for kernel messages from exit function using dmesg command. .. code-block:: shell test@test-V520-15IKL:~$ sudo dmesg [14118.693977] Destroying kthread [14119.599136] Cancel the kthread delayed work [14119.599537] Destroyed kthread and worker .. _p5_delayedkthreadworker_67: .. tab-set:: .. tab-item:: Example 3: Modify delay of work using kthread_mod_delayed_work * In this example let's see how to modify delay of work using kthread_mod_delayed_work .. _p5_delayedkthreadworker_68: .. tab-set:: .. tab-item:: List of headers * Include the follow header files(.h) to refer the API being used for the execution. .. code-block:: c #include #include #include #include #include #include #include .. _p5_delayedkthreadworker_69: .. tab-set:: .. tab-item:: Module macros * Add the following module macros to display information about the license, author and description about the module. .. code-block:: c MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linux Usr"); MODULE_DESCRIPTION("example of kthread_mod_delayed_work"); .. _p5_delayedkthreadworker_70: .. tab-set:: .. tab-item:: Initialize thread variables * Declare the thread variables which we are going to create and use in this example .. code-block:: c bool ret_val; static struct task_struct *my_thread; static struct kthread_worker *my_worker; struct my_work { struct kthread_work my_kthread_delayed_work; int i; }; .. _p5_delayedkthreadworker_71: .. tab-set:: .. tab-item:: Module init function * Add the module init function which will be executed once we load the kernel module using insmod command. .. code-block:: c static int __init kthread_mod_delayed_work_init(void) { pr_info("Inside kthread init function\n"); thread_start(); return 0; } .. _p5_delayedkthreadworker_72: .. tab-set:: .. tab-item:: thread start function * Add the thread start function in which the thread is created and starts its execution. .. code-block:: c void thread_start(void) { my_thread = kthread_run(my_thread_fun,NULL,"kthread_mod_delayed_work thread example"); if (IS_ERR(my_thread)) pr_info("Error in creating thread\n"); else pr_info("Created Thread\n"); } .. _p5_delayedkthreadworker_73: .. tab-set:: .. tab-item:: Module exit function * Add the module exit function which will be executed once we unload the kernel module using rmmod command. .. code-block:: c static void __exit kthread_mod_delayed_work_exit(void) { pr_info("Inside kthread exit function\n"); thread_stop(); } .. _p5_delayedkthreadworker_74: .. tab-set:: .. tab-item:: thread stop function * Add the thread stop function which destroys worker,thread and stops the execution. .. code-block:: c void thread_stop(void) { if (my_thread) { kthread_stop(my_thread); kthread_destroy_worker(my_worker); pr_info("Destroyed threads and worker\n"); } } .. _p5_delayedkthreadworker_75: .. tab-set:: .. tab-item:: Thread function API * Add the thread function API which will be called as soon as the kthread is created and is in running state. .. code-block:: c int def_thread_fun(void *data) { struct my_work my_def_work; kthread_init_delayed_work(&my_def_work.my_kthread_delayed_work,def_delayed_work_function); pr_info("Initializing kthread work\n"); worker = kthread_create_worker(0,"kthread_mod_delayed_work worker example"); if (IS_ERR(worker)) pr_info("Error creating worker\n"); else pr_info("Created kthread worker\n"); ret_val = kthread_queue_delayed_work(worker,&my_def_work.my_kthread_delayed_work,msecs_to_jiffies(5000)); if (ret_val) pr_info("Queue the work to worker\n"); else pr_info("Work is pending\n"); while (!kthread_should_stop()) { pr_info("thread execution\n"); ret_val = kthread_cancel_delayed_work_sync(&my_def_work.my_kthread_delayed_work); if (!ret_val) { kthread_mod_delayed_work(worker,&my_def_work.my_kthread_delayed_work,msecs_to_jiffies(10)); pr_info("Modified the time delay for the queued work\n"); msleep(1000); kthread_stop(my_thread); } } return 0; } .. _p5_delayedkthreadworker_76: .. tab-set:: .. tab-item:: Work function API * Add the work function API which is executed once the work is queued to worker. .. code-block:: c void def_delayed_work_function(struct kthread_work *work) { struct my_work *my_data; my_data = kmalloc(sizeof(struct my_work*),GFP_KERNEL); pr_info("Inside work function\n"); my_data->i = 0; while (my_data->i <= 10) { pr_info("my_data->i = %d\n",my_data->i); my_data->i++; } } .. _p5_delayedkthreadworker_77: .. tab-set:: .. tab-item:: Driver entry points * Add the driver entry points which will be executed once the module is inserted or removed from the kernel. .. code-block:: c module_init(kthread_mod_delayed_work_init); module_exit(kthread_mod_delayed_work_exit); .. _p5_delayedkthreadworker_78: .. tab-set:: .. tab-item:: See the full program below .. tab-set:: .. tab-item:: kthread.c .. literalinclude:: p5_delayedkthreadworker/kthread_mod_delayed_work/kthread.c :language: c :linenos: .. _p5_delayedkthreadworker_79: .. tab-set:: .. tab-item:: Makefile .. literalinclude:: p5_delayedkthreadworker/kthread_mod_delayed_work/Makefile :language: c :linenos: .. _p5_delayedkthreadworker_80: .. tab-set:: .. tab-item:: Compile and load the module * Run make to compile the kernel source and generate the .ko image. .. code-block:: shell make -C /lib/modules/6.7.9/build M=$HOME/kthread_examples/ make[1]: Entering directory '/usr/src/linux-headers-6.7.9' warning: the compiler differs from the one used to build the kernel The kernel was built by: x86_64-linux-gnu-gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0 You are using: gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0 CC [M] $HOME/kthread_examples/kthread.o MODPOST $HOME/kthread_examples/Module.symvers CC [M] $HOME/kthread_examples/kthread.mod.o LD [M] $HOME/kthread_examples/kthread.ko BTF [M] $HOME/kthread_examples/kthread.ko Skipping BTF generation for $HOME/kthread_examples/kthread.ko due to unavailability of vmlinux make[1]: Leaving directory '/usr/src/linux-headers-6.7.9' * Check if the .ko is generated or not using ls command. .. code-block:: shell test@test-V520-15IKL:~$ ls -l total 360 -rw-rw-r-- 1 test test 713 Mar 18 16:06 kthread.c -rw-rw-r-- 1 test test 169784 Mar 18 16:08 kthread.ko -rw-rw-r-- 1 test test 58 Mar 18 16:08 kthread.mod -rw-rw-r-- 1 test test 1047 Mar 18 16:08 kthread.mod.c -rw-rw-r-- 1 test test 96512 Mar 18 16:08 kthread.mod.o -rw-rw-r-- 1 test test 74696 Mar 18 16:08 kthread.o -rw-rw-r-- 1 test test 161 Mar 18 16:00 Makefile -rw-rw-r-- 1 test test 58 Mar 18 16:08 modules.order -rw-rw-r-- 1 test test 0 Mar 18 16:08 Module.symvers * Run modinfo command to get the information about the kernel module. .. code-block:: shell test@test-V520-15IKL:~/.../tc_1$ modinfo kthread.ko filename: $HOME/kthread_examples/kthread.ko description: Example of kthread_mod_delayed_work author: Linux Usr license: GPL srcversion: 8D2147F67AB01CF0E482DAC depends: retpoline: Y name: kthread vermagic: 6.7.9 SMP preempt mod_unload modversions * insert the module using insmod command. .. code-block:: shell test@test-V520-15IKL:~$ sudo insmod ./kthread.ko * check if the module is loaded or not using lsmod command. .. code-block:: shell test@test-V520-15IKL:~$ sudo lsmod | grep kthread kthread 16384 0 * check if the thread is created or not using ps command. .. code-block:: shell test@test-V520-15IKL:~$ ps -N | grep kthread_mod_delayed_work 5207 ? 00:00:00 kthread_mod_delayed_work thread example 5208 ? 00:00:00 kthread_mod_delayed_work worker example * check for the kernel messages from init function and thread function once the module is loaded and thread is created. .. code-block:: shell test@test-V520-15IKL:~$ sudo dmesg [ 665.913373] Inside kthread_init function [ 665.913463] Created kthread [ 665.913469] Initializing kthread work [ 665.913518] Created kthread worker [ 665.913521] Queue the work to worker [ 665.913526] thread execution [ 665.913529] thread execution [ 665.913530] Modified the time delay for the queued work [ 665.930962] Inside work function [ 665.930967] my_data->i = 0 [ 665.930970] my_data->i = 1 [ 665.930972] my_data->i = 2 * remove the module from kernel using rmmod command. .. code-block:: shell test@test-V520-15IKL:~$ sudo rmmod kthread * check if the module is still loaded after removing the kernel module using lsmod if it is not displayed in lsmod output it is verified that the module is removed successfully. .. code-block:: shell test@test-V520-15IKL:~$ sudo lsmod | grep kthread test@test-V520-15IKL:~$ * check if the thread is destroyed using ps command if it is not displayed in ps output we can confirm that the thread is destroyed successfully. .. code-block:: shell test@test-V520-15IKL:~$ ps -N | grep kthread_mod_delayed_work test@test-V520-15IKL:~$ * Check for kernel messages from exit function using dmesg command. .. code-block:: shell test@test-V520-15IKL:~$ sudo dmesg [ 676.799621] Inside kthread_exit function [ 676.799898] Destroyed kthread and worker .. _p5_delayedkthreadworker_37: .. tab-set:: .. tab-item:: Example 4: Queue multiple delayed works using kthread_queue_delayed_work * In this example let's see how to queue multiple delayed works using kthread_queue_delayed_work .. _p5_delayedkthreadworker_38: .. tab-set:: .. tab-item:: List of headers * Include the follow header files(.h) to refer the API being used for the execution. .. code-block:: c #include #include #include #include #include #include #include .. _p5_delayedkthreadworker_39: .. tab-set:: .. tab-item:: Module macros * Add the following module macros to display information about the license, author and description about the module. .. code-block:: c MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linux Usr"); MODULE_DESCRIPTION("example of kthread_queue_delayed_work"); .. _p5_delayedkthreadworker_40: .. tab-set:: .. tab-item:: Initialize thread variables * Declare the thread variables which we are going to create and use in this example .. code-block:: c bool ret_val; static struct task_struct *my_thread; static struct kthread_worker *my_worker; struct my_work { struct kthread_work my_kthread_delayed_work; int i; }; .. _p5_delayedkthreadworker_41: .. tab-set:: .. tab-item:: Module init function * Add the module init function which will be executed once we load the kernel module using insmod command. .. code-block:: c static int __init kthread_queue_delayed_work_init(void) { pr_info("Inside kthread init function\n"); thread_start(); return 0; } .. _p5_delayedkthreadworker_55: .. tab-set:: .. tab-item:: thread start function * Add the thread start function in which the thread is created and starts its execution. .. code-block:: c void thread_start(void) { my_thread = kthread_run(my_thread_fun,NULL,"kthread_queue_delayed_work thread example"); if (IS_ERR(my_thread)) pr_info("Error in creating thread\n"); else pr_info("Thread created successfully\n"); } .. _p5_delayedkthreadworker_42: .. tab-set:: .. tab-item:: Module exit function * Add the module exit function which will be executed once we unload the kernel module using rmmod command. .. code-block:: c static void __exit kthread_queue_delayed_work_exit(void) { pr_info("Inside kthread exit function\n"); thread_stop(); } .. _p5_delayedkthreadworker_56: .. tab-set:: .. tab-item:: thread stop function * Add the thread stop function which destroys worker,thread and stops the execution. .. code-block:: c void thread_stop(void) { if (my_thread) { kthread_stop(my_thread); kthread_destroy_worker(my_worker); pr_info("Destroyed threads and worker\n"); } } .. _p5_delayedkthreadworker_43: .. tab-set:: .. tab-item:: Thread function API * Add the thread function API which will be called as soon as the kthread is created and is in running state. .. code-block:: c int my_thread_fun(void *data) { struct my_work my_def_work_1; struct my_work my_def_work_2; kthread_init_delayed_work(&my_def_work_1.my_kthread_delayed_work,def_work_fn_1); pr_info("kthread work 1 intialized\n"); my_worker = kthread_create_worker(0,"kthread_queue_delayed_work worker example"); if (IS_ERR(my_worker)) pr_info("error in creating kthread_worker\n"); else pr_info("kthread worker created\n"); ret_val = kthread_queue_delayed_work(my_worker,&my_def_work_1.my_kthread_delayed_work,msecs_to_jiffies(1000)); if (ret_val) pr_info("kthread work 1 is queued to worker\n"); else pr_info("work is in pending state\n"); kthread_init_delayed_work(&my_def_work_2.my_kthread_delayed_work,def_work_fn_2); pr_info("kthread_work_2_initialized\n"); ret_val = kthread_queue_delayed_work(my_worker,&my_def_work_2.my_kthread_delayed_work,msecs_to_jiffies(10)); if (ret_val) pr_info("kthread work 2 is queued to worker\n"); else pr_info("work is in pending state\n"); while(!kthread_should_stop()) { pr_info("thread execution\n"); msleep(5000); } return 0; } .. _p5_delayedkthreadworker_64: .. tab-set:: .. tab-item:: Work function API * Add the work function API which is executed once the work is queued to worker. .. code-block:: c void def_work_fn_1(struct kthread_work *work) { struct my_work *my_work_fn_1; my_work_fn_1 = kmalloc(sizeof(struct my_work*),GFP_KERNEL); pr_info("Inside work function 1\n"); my_work_fn_1->i = 0; while (my_work_fn_1->i <= 3) { pr_info("my_work_fn_1 = %d\n",my_work_fn_1->i); my_work_fn_1->i++; msleep(100); } } void def_work_fn_2(struct kthread_work *work) { struct my_work *my_work_fn_2; my_work_fn_2 = kmalloc(sizeof(struct my_work*),GFP_KERNEL); pr_info("Inside work function 2\n"); my_work_fn_2->i=3; while (my_work_fn_2->i >= 0) { pr_info("my_work_fn_2 = %d\n",my_work_fn_2->i); my_work_fn_2->i--; msleep(100); } } .. _p5_delayedkthreadworker_44: .. tab-set:: .. tab-item:: Driver entry points * Add the driver entry points which will be executed once the module is inserted or removed from the kernel. .. code-block:: c module_init(kthread_queue_delayed_work_init); module_exit(kthread_queue_delayed_work_exit); .. _p5_delayedkthreadworker_45: .. tab-set:: .. tab-item:: See the full program below .. tab-set:: .. tab-item:: kthread.c .. literalinclude:: p5_delayedkthreadworker/kthread_queue_delayed_work/kthread.c :language: c :linenos: .. _p5_delayedkthreadworker_46: .. tab-set:: .. tab-item:: Makefile .. literalinclude:: p5_delayedkthreadworker/kthread_queue_delayed_work/Makefile :language: c :linenos: .. _p5_delayedkthreadworker_47: .. tab-set:: .. tab-item:: Compile and load the module * Run make to compile the kernel source and generate the .ko image. .. code-block:: shell make -C /lib/modules/6.7.9/build M=$HOME/kthread_examples/ make[1]: Entering directory '/usr/src/linux-headers-6.7.9' warning: the compiler differs from the one used to build the kernel The kernel was built by: x86_64-linux-gnu-gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0 You are using: gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0 CC [M] $HOME/kthread_examples/kthread.o MODPOST $HOME/kthread_examples/Module.symvers CC [M] $HOME/kthread_examples/kthread.mod.o LD [M] $HOME/kthread_examples/kthread.ko BTF [M] $HOME/kthread_examples/kthread.ko Skipping BTF generation for $HOME/kthread_examples/kthread.ko due to unavailability of vmlinux make[1]: Leaving directory '/usr/src/linux-headers-6.7.9' * Check if the .ko is generated or not using ls command. .. code-block:: shell test@test-V520-15IKL:~$ ls -l total 360 -rw-rw-r-- 1 test test 713 Mar 18 16:06 kthread.c -rw-rw-r-- 1 test test 169784 Mar 18 16:08 kthread.ko -rw-rw-r-- 1 test test 58 Mar 18 16:08 kthread.mod -rw-rw-r-- 1 test test 1047 Mar 18 16:08 kthread.mod.c -rw-rw-r-- 1 test test 96512 Mar 18 16:08 kthread.mod.o -rw-rw-r-- 1 test test 74696 Mar 18 16:08 kthread.o -rw-rw-r-- 1 test test 161 Mar 18 16:00 Makefile -rw-rw-r-- 1 test test 58 Mar 18 16:08 modules.order -rw-rw-r-- 1 test test 0 Mar 18 16:08 Module.symvers * Run modinfo command to get the information about the kernel module. .. code-block:: shell test@test-V520-15IKL:~/.../tc_1$ modinfo kthread.ko filename: $HOME/kthread_examples/kthread.ko description: Example of kthread_queue_delayed_work author: Linux Usr license: GPL srcversion: 8D2147F67AB01CF0E482DAC depends: retpoline: Y name: kthread vermagic: 6.7.9 SMP preempt mod_unload modversions * insert the module using insmod command. .. code-block:: shell test@test-V520-15IKL:~$ sudo insmod ./kthread.ko * check if the module is loaded or not using lsmod command. .. code-block:: shell test@test-V520-15IKL:~$ sudo lsmod | grep kthread kthread 16384 0 * check if the thread is created or not using ps command. .. code-block:: shell test@test-V520-15IKL:~$ ps -N | grep kthread_queue_delayed_work 6108 ? 00:00:00 kthread_queue_delayed_work thread example 6109 ? 00:00:00 kthread_queue_delayed_work worker example * check for the kernel messages from init function and thread function once the module is loaded and thread is created. .. code-block:: shell test@test-V520-15IKL:~$ sudo dmesg [ 1196.526494] Inside kthread init function [ 1196.526552] Thread created successfully [ 1196.526556] kthread work 1 intialized [ 1196.526596] kthread worker created [ 1196.526602] kthread work 1 is queued to worker [ 1196.526603] kthread_work_2_initialized [ 1196.526605] kthread work 2 is queued to worker [ 1196.526606] thread execution [ 1196.539529] Inside work function 2 [ 1196.539534] my_work_fn_2 = 3 [ 1196.539537] my_work_fn_2 = 2 [ 1196.539539] my_work_fn_2 = 1 [ 1196.539541] my_work_fn_2 = 0 [ 1197.555661] Inside work function 1 [ 1197.555666] my_work_fn_1 = 0 [ 1197.555668] my_work_fn_1 = 1 [ 1197.555669] my_work_fn_1 = 2 [ 1197.555671] my_work_fn_1 = 3 * remove the module from kernel using rmmod command. .. code-block:: shell test@test-V520-15IKL:~$ sudo rmmod kthread * check if the module is still loaded after removing the kernel module using lsmod if it is not displayed in lsmod output it is verified that the module is removed successfully. .. code-block:: shell test@test-V520-15IKL:~$ sudo lsmod | grep kthread test@test-V520-15IKL:~$ * check if the thread is destroyed using ps command if it is not displayed in ps output we can confirm that the thread is destroyed successfully. .. code-block:: shell test@test-V520-15IKL:~$ ps -N | grep kthread_queue_delayed_work test@test-V520-15IKL:~$ * Check for kernel messages from exit function using dmesg command. .. code-block:: shell test@test-V520-15IKL:~$ sudo dmesg [ 1198.643574] Destroying threads [ 1201.647894] Destroyed threads and worker .. _p5_delayedkthreadworker_48: .. tab-set:: .. tab-item:: Summary of Kthread APIs ================================= ================================================== kthread API Learning ================================= ================================================== kthread_create_worker Create kthread worker kthread_init_delayed_work Create kthread delayed work kthread_queue_delayed_work Queue work to worker kthread_cancel_delayed_work_sync Cancel the kthread work and wait for it to finish kthread_run Create and wake a thread kthread_destroy_worker Destroy kthread worker ================================= ================================================== .. _p5_delayedkthreadworker_49: .. tab-set:: .. tab-item:: Summary of miscellaneous APIs =============================== =========================================================================================== API Learning =============================== =========================================================================================== MODULE_LICENSE Used to denote the license used in the kernel module MODULE_AUTHOR Used to mention the author of the kernel module MODULE_DESCRIPTION Used to describe what the module does IS_ERR Detects an error pointer container_of cast a member of the structure to the containing structure kmalloc Allocate kernel memory wake_up_process wake up a specific process msleep will put in sleep for a certain amount of msecs time. msecs_to_jiffies convert milliseconds to jiffies module_init Driver initialization entry point module_exit Driver exit entry point pr_info Print an info-level message =============================== ===========================================================================================