// Kernel thread synchronization with
wait queue
/*
This code post is useful to learn the synchronization behavior of kernel thread with respect to synchronization
Theory:
Threads synchronization is based on event, 2 threads use completion event for synchronization and unblock the other thread
Blocked thread waiting for an event
waits in a wait queue. when it receives the event it is eligible by
the scheduler to run
Task in blocked state will expect some
condition to be true (non zero)
wait queues in linux are defined by
wait queue header which is a list_head node (Double linked list node) linked to wait_queue_t nodes which holds a function pointer to the task
wait_event_interruptible puts the task into waitqueue
wake_up_interruptible wakes the task on wakeup event
Code Explanation:
Initialization creates 2 instances of
kernel thread (tone, tzero)with same kernel function (kthread
function)
The kernel threads tone and tzero
should alternatively display their names one and zero
Thread parameter structure is
assocaited with each thread instance kthread_data
Thread parameters are
1. name
2. wait queue to synchronize the two
threads
3. condition variable used with the
wait queue
4. Pointer to other thread's parameter
kthread_function?
conditionally block on a wait queue
using wait_event_interruptible
output the name
wait for the event in wait_queue
unblock the other thread using
wake_up_interruptible
tone is the first thread with
condition variable to true (1 - non-zero)
tzero thread with condition variable
initialized to false (0 - zero)
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/delay.h>
MODULE_LICENSE("Dual BSD/GPL");
struct kthr_data {
const char *name;
//wq<--wqh-->wq
wait_queue_head_t thrdwq; // kernel
thread waits on this queue //wait_queue_head_t is the list head other
nodes are wait_queue_t //nodes which holds the task (function pointer)
int condition;
struct kthr_data *datalink;
};
static struct kthr_data done, dzero;
int kthread_function(void* data)
{
struct kthr_data *pdata = (struct
kthr_data*)data; // this data depends on the kernel thread running
"one"/"zero"
while(1)
{
printk("wait(%s)",
pdata->name);
wait_event_interruptible(pdata->thrdwq, pdata->condition);
pdata->condition = 0;
printk("%s\n",pdata->name);
mdelay(500);
msleep(1);
pdata->datalink->condition
= 1;
printk("wakeup (%s)\n",
pdata->name);
wake_up_interruptible(&pdata->datalink->thrdwq);//wake up the //task waiting in queue
if(kthread_should_stop())
break;
}
return 0;
}
struct task_struct *tone, *tzero;
int __init kthread_init(void)
{
printk("\nkthread init");
init_waitqueue_head(&done.thrdwq);
init_waitqueue_head(&dzero.thrdwq);
done.condition = 1;
dzero.condition = 0;
done.name = "one";
dzero.name = "zero";
done.datalink = &dzero;
dzero.datalink = &done;
tone =
kthread_run(kthread_function, &done, "one");
tzero =
kthread_run(kthread_function, &dzero, "zero");
return 0;
}
void __exit kthread_exit(void)
{
printk("\nkernel exit
thread");
kthread_stop(tone);
kthread_stop(tzero);
}
module_init(kthread_init);
module_exit(kthread_exit);
//output: one zero one zero ...
No comments:
Post a Comment