Wednesday, 5 June 2013

LINUX KERNEL THREAD SYNCHRONIZATION WITH WAITQUEUE


// 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