It’s been quite some time since I touched linux kernel modules, right now I’m revisiting the concepts once more. In this post I’m writing down the bullet points for creating the kernel threads.
To create a linux kernel thread, we need to:
- Include:
linux/kthread.h
- Include:
linux/sched.h
- Create:
struct task_struct *
this structure is defined inlinux/sched.h
. - Create a function that you need to execute from the thread: The signature of that function needs to be
int function_name (void *data)
- Create a
kthread
using :kthread_create
fromlinux/kthread.h
. - Move the thread to the set of runnable processes using
wake_up_process
. - Stop the thread before exiting the module using
kthread_stop
.
Putting everything together,
Following is the (same old 😅) example program to create multiple threads from a kernel module.
kthread_demo.c
#include<linux/module.h> // included for all kernel modules
#include<linux/init.h> // included for __init and __exit macros
#include<linux/kthread.h> // included for threading related functions
#include<linux/sched.h> // included to create tesk_struct
#include<linux/delay.h> // included for the sleep/delay function in the thread
// array for task_struct to hold task info
static struct task_struct kth_arr[4];
// long running function to be executed inside a thread, this will run for 30 secs.
int thread_function(void * idx) {
unsigned int i = 0;
int t_id = * (int * ) idx;
// kthread_should_stop call is important.
while (!kthread_should_stop()) {
printk(KERN_INFO "Thread %d Still running...! %d secs\n", t_id, i);
i++;
if (i == 30)
break;
msleep(1000);
}
printk(KERN_INFO "thread %d stopped\n", t_id);
return 0;
}
// initialize one thread at a time.
int initialize_thread(struct task_struct * kth, int idx) {
char th_name[20];
sprintf(th_name, "kthread_%d", idx);
kth = kthread_create(thread_function, & idx, (const char * ) th_name);
if (kth != NULL) {
wake_up_process(kth);
printk(KERN_INFO "%s is running\n", th_name);
} else {
printk(KERN_INFO "kthread %s could not be created\n", th_name);
return -1;
}
return 0;
}
// module init function
static int __init mod_init(void) {
int i = 0;
printk(KERN_INFO "Initializing thread module\n");
for (i = 0; i < 4; i++) {
// initialize one thread at a time.
if (initialize_thread( & kth_arr[i], i) == -1) {
return -1;
}
}
printk(KERN_INFO "all of the threads are running\n");
return 0;
}
// module exit function.
static void __exit mod_exit(void) {
int i = 0;
int ret = 0;
printk(KERN_INFO "exiting thread module\n");
for (i = 0; i < 4; i++) {
// stop all of the threads before removing the module.
ret = kthread_stop( & kth_arr[i]);
if (!ret) {
printk("can't stop thread %d", i);
}
}
printk(KERN_INFO "stopped all of the threads\n");
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("GIRISH JOSHI");
MODULE_DESCRIPTION("KTHREAD demo");
module_init(mod_init);
module_exit(mod_exit);
and of course the makefile looks like
obj-m+=kthread_demo.o
all:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean