Module with Two Kthread - mutex
In this program, you are going to learn
How to create two threads ?
How to use below APIs ?
Here is the explanation of thread program part by part
This sections contains all the headers which contains the definition of the APIs used in the kernel thread program.
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/mutex.h>
Initialize all the required thread and spinlock variables.
static struct task_struct *thread1;
static struct task_struct *thread2;
DEFINE_MUTEX(mutex);
struct node {
int data;
struct list_head list;
};
LIST_HEAD(my_list);
DEFINE_MUTEX
macro is used to declare a mutex.LIST_HEAD
is used to initialize a list head structure.
The module marco is initialized which lists out the license of the module, author of the module and description of the module.
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux_usr");
MODULE_DESCRIPTION("Two kthreads - SLL - mutex");
module-init function contains the instructions to create the thread and execute the thread via the corresponding thread function.
static int __init thread_init(void)
{
struct node *node1;
struct node *node2;
pr_info("Driver Loaded...\n");
node1 = kmalloc(sizeof(struct node), GFP_KERNEL);
node1->data = 1;
INIT_LIST_HEAD(&node1->list);
list_add_tail(&node1->list, &my_list);
node2 = kmalloc(sizeof(struct node), GFP_KERNEL);
node2->data = 2;
INIT_LIST_HEAD(&node2->list);
list_add_tail(&node2->list, &my_list);
thread1 = kthread_run(thread_fun1, NULL, "thread1");
if (IS_ERR(thread1)) {
pr_alert("Failed to create thraed1");
return PTR_ERR(thread1);
}
thread2 = kthread_run(thread_fun2, NULL, "thread2");
if (IS_ERR(thread1)) {
pr_alert("Failed to create thraed2");
return PTR_ERR(thread2);
}
return 0;
}
In this init function,
node1
,node2
is initialized, allocated memory dynamically and added to the list.thread1
,thread2
is created and the corresponding thread APIs is passed as an argument.
module-exit function is used to stop and clean up all the thread process going on from the start of module-init function.
static void __exit thread_exit(void)
{
struct node *curr_node, *next_node;
kthread_stop(thread1);
kthread_stop(thread2);
list_for_each_entry_safe(curr_node, next_node, &my_list, list) {
list_del(&curr_node->list);
kfree(curr_node);
}
pr_info("Driver Unloaded...\n");
}
In this exit function,
threads which are created in init function are being terminated.
each entry in the list are being freed.
thread function will execute a print statement until the thread is stopped and until that the thread will execute.
static int thread_fun1(void *data)
{
struct node *new_node;
while (!kthread_should_stop()) {
mutex_lock(&mutex);
list_for_each_entry(new_node, &my_list, list) {
new_node->data++;
pr_info("Executing thread function 1 : %d\n", new_node->data);
}
mutex_unlock(&mutex);
msleep(5000);
}
return 0;
}
static int thread_fun2(void *data)
{
struct node *new_node;
while (!kthread_should_stop()) {
mutex_lock(&mutex);
list_for_each_entry(new_node, &my_list, list) {
new_node->data++;
pr_info("Executing thread function 2 : %d\n", new_node->data);
}
mutex_unlock(&mutex);
msleep(5000);
}
return 0;
}
In this thread fun1 and thread fun2,
A new node is being created.
whenever the mutex is locked the new node is being added to the list.
once the new node is added to the list the mutex is unlocked so that next set of operations can access the resources.
init and exit function name should be added in the module_init and module_exit parameter.
module_init(thread_init);
module_exit(thread_exit);
1#include <linux/init.h>
2#include <linux/kernel.h>
3#include <linux/module.h>
4#include <linux/cdev.h>
5#include <linux/device.h>
6#include <linux/fs.h>
7#include <linux/uaccess.h>
8#include <linux/kthread.h>
9#include <linux/delay.h>
10#include <linux/interrupt.h>
11#include <linux/list.h>
12#include <linux/slab.h>
13#include <linux/mutex.h>
14
15MODULE_LICENSE("GPL");
16MODULE_AUTHOR("Linux_usr");
17MODULE_DESCRIPTION("Two kthreads - SLL - mutex");
18
19static struct task_struct *thread1;
20static struct task_struct *thread2;
21
22DEFINE_MUTEX(mutex);
23
24struct node {
25 int data;
26 struct list_head list;
27};
28
29LIST_HEAD(my_list);
30
31static int thread_fun1(void *data)
32{
33 struct node *new_node;
34
35 while (!kthread_should_stop()) {
36 mutex_lock(&mutex);
37 list_for_each_entry(new_node, &my_list, list) {
38 new_node->data++;
39 pr_info("Executing thread function 1 : %d\n", new_node->data);
40 }
41 mutex_unlock(&mutex);
42 msleep(5000);
43 }
44 return 0;
45}
46
47static int thread_fun2(void *data)
48{
49 struct node *new_node;
50
51 while (!kthread_should_stop()) {
52 mutex_lock(&mutex);
53 list_for_each_entry(new_node, &my_list, list) {
54 new_node->data++;
55 pr_info("Executing thread function 2 : %d\n", new_node->data);
56 }
57 mutex_unlock(&mutex);
58 msleep(5000);
59 }
60 return 0;
61}
62
63static int __init thread_init(void)
64{
65 struct node *node1;
66 struct node *node2;
67
68 pr_info("Driver Loaded...\n");
69
70 node1 = kmalloc(sizeof(struct node), GFP_KERNEL);
71 node1->data = 1;
72 INIT_LIST_HEAD(&node1->list);
73 list_add_tail(&node1->list, &my_list);
74
75 node2 = kmalloc(sizeof(struct node), GFP_KERNEL);
76 node2->data = 2;
77 INIT_LIST_HEAD(&node2->list);
78 list_add_tail(&node2->list, &my_list);
79
80 thread1 = kthread_run(thread_fun1, NULL, "thread1");
81 if (IS_ERR(thread1)) {
82 pr_alert("Failed to create thraed1");
83 return PTR_ERR(thread1);
84 }
85
86 thread2 = kthread_run(thread_fun2, NULL, "thread2");
87 if (IS_ERR(thread1)) {
88 pr_alert("Failed to create thraed2");
89 return PTR_ERR(thread2);
90 }
91 return 0;
92}
93
94static void __exit thread_exit(void)
95{
96 struct node *curr_node, *next_node;
97
98 kthread_stop(thread1);
99 kthread_stop(thread2);
100 list_for_each_entry_safe(curr_node, next_node, &my_list, list) {
101 list_del(&curr_node->list);
102 kfree(curr_node);
103 }
104 pr_info("Driver Unloaded...\n");
105}
106
107module_init(thread_init);
108module_exit(thread_exit);
1obj-m += threads.o
2all:
3 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
4clean:
5 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Run make to compile the kernel module.
$ make
make -C /lib/modules/5.4.0-150-generic/build M=$HOME/kernel_thread modules
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-150-generic'
CC [M] $HOME/kernel_thread/thread.o
Building modules, stage 2.
MODPOST 1 modules
CC [M] $HOME/kernel_thread/thread.mod.o
LD [M] $HOME/kernel_thread/thread.ko
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-150-generic'
Check if thread.ko is generated or not.
$ ls -l
total 408
-rwxrwxrwx 1 test test 1388 Sep 12 16:13 threads.c
-rw-rw-r-- 1 test test 194592 Sep 12 16:14 threads.ko
-rw-rw-r-- 1 test test 142 Sep 12 16:14 threads.mod
-rw-rw-r-- 1 test test 1066 Sep 12 16:14 threads.mod.c
-rw-rw-r-- 1 test test 93872 Sep 12 16:14 threads.mod.o
-rw-rw-r-- 1 test test 102136 Sep 12 16:14 threads.o
-rwxrwxrwx 1 test test 182 Sep 12 16:08 Makefile
-rw-rw-r-- 1 test test 142 Sep 12 16:14 modules.order
-rw-rw-r-- 1 test test 0 Sep 12 16:14 Module.symvers
-rwxrwxrwx 1 test test 2144 Sep 12 16:12 README
Run insmod to load the kernel module to linux kernel.
$ sudo insmod ./threads.ko
Check for kernel messages to verify if the module is loaded or not.
$ dmesg
[30043.211194] Driver Loaded...
[30043.211240] Executing thread function 1 : 2
[30043.211241] Executing thread function 1 : 3
[30043.211258] Executing thread function 2 : 3
[30043.211259] Executing thread function 2 : 4
[30048.366455] Executing thread function 1 : 4
[30048.366458] Executing thread function 1 : 5
[30048.366462] Executing thread function 2 : 5
[30048.366464] Executing thread function 2 : 6
Run lsmod to check for the kernel module.
$ lsmod | grep threads
threads 16384 0
Unload the module using rmmod command.
$ sudo rmmod threads
Check kernel messages to see if the module is unloaded or not.
$ dmesg
[30043.211194] Driver Loaded...
[30043.211240] Executing thread function 1 : 2
[30043.211241] Executing thread function 1 : 3
[30043.211258] Executing thread function 2 : 3
[30043.211259] Executing thread function 2 : 4
[30048.366455] Executing thread function 1 : 4
[30048.366458] Executing thread function 1 : 5
[30048.366462] Executing thread function 2 : 5
[30048.366464] Executing thread function 2 : 6
[30053.390584] Driver Unloaded...
We can also get the information about the module using
modinfo
command.
$ modinfo threads.ko
filename: threads.ko
description: Two kthreads - SLL - mutex
author: Linux_usr
license: GPL
srcversion: CCE53406D9BB7F8DAD8150C
depends:
retpoline: Y
name: threads
vermagic: 5.4.0-150-generic SMP mod_unload modversions
# |
Learning |
---|---|
MODULE_DESCRIPTION |
used to describe what the module does |
DEFINE_MUTEX |
To declare a mutex variable |
LIST_HEAD |
A list is headed by a structure defined by the LIST_HEAD macro |
mutex_lock |
Acquires given lock |
list_for_each_entry |
iterate over list of given type |
mutex_unlock |
Releases given lock |
INIT_LIST_HEAD |
Initialize a list_head structure |
list_add_tail |
add a new entry |
kmalloc |
kernel memory allocation function |
kthread_run |
create and wake a thread |
IS_ERR |
used to check, Returns non-0 value if the ptr is an error, Otherwise 0 if it’s not an error |
pr_alert |
Print an alert-level message |
PTR_ERR |
used to print, Current value of the pointer |
kthread_stop |
stop a thread created by kthread_create. |
list_for_each_entry_safe |
iterate over list of given type safe against removal of list entry |
list_del |
deletes entry from list |
kfree |
free previously allocated memory by kmalloc |