// Kernel thread synchronization with semaphore
// Theory:
//Two threads can be synchornized by semaphore, blocked threads are pushed //into semaphore queue
// Theory:
//Two threads can be synchornized by semaphore, blocked threads are pushed //into semaphore queue
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/semaphore.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/semaphore.h>
#include <linux/delay.h>
MODULE_LICENSE("Dual BSD/GPL");
struct kthr_data
{
const char *name; //kthread name
struct semaphore *sem1;
struct semaphore *sem2;
};
static struct kthr_data dking, dqueen;
static struct semaphore kingsem, queensem;
static struct task_struct *tking, *tqueen;
/* our case:
down dking sem1 decrements to make it (1->0)zero and runs the thread tking unlocked to locked state //king works
up dking sem2 increments to make it (0->1) unlock because sem2 waitlist is still empty
down dqueen sem1 decrements to make it (1->0)zero and runs the thread tking unlocked to locked state //queen works
up dqueen sem2 increments to make it (0->1) unlock
*/
int kthread_function(void *data)
{
struct kthr_data *pdata = (struct kthr_data*)data;
while(1)
{
//down operation decrements the counter, if the count is 0 then down operation over the semaphore
//1. blocks the calling kernel thread
//2. Insert it into task structure to the queue of the semaphore
//3. schedule another task
down_interruptible(pdata->sem1); //uninterruptible sleep in sem->wait list when sem1 is zero
printk("%s\n", pdata->name);
mdelay(499);
msleep(1);
up(pdata->sem2);
//if the semaphore wait queue is not empty then it pick a task and make it runnable else increment the counter
//if sem->wait list is empty increment sem->count and leave if sem->count is 0 remove the first waiter structure from the sem queue
if(kthread_should_stop())
break;
}
return 0;
}
struct task_struct *ts;
static int __init kthr_init(void)
{
printk("kthread init called");
//semaphore is an object consists of a counter and a queue of waiting tasks
sema_init(&kingsem, 1); //unlocked state
sema_init(&queensem, 0); //locked state
dking.name = "king";
dqueen.name = "queen";
dking.sem1 = &kingsem;
dking.sem2 = &queensem;
dqueen.sem1 = &queensem;
dqueen.sem2 = &kingsem;
tking = kthread_run(kthread_function, &dking, "king");
tqueen = kthread_run(kthread_function, &dqueen, "queen");
return 0;
}
void __exit kthr_exit(void)
{
printk("tking_stop called");
kthread_stop(tking);
printk("tqueen_stop called");
kthread_stop(tqueen);
}
module_init(kthr_init);
module_exit(kthr_exit);
struct kthr_data
{
const char *name; //kthread name
struct semaphore *sem1;
struct semaphore *sem2;
};
static struct kthr_data dking, dqueen;
static struct semaphore kingsem, queensem;
static struct task_struct *tking, *tqueen;
/* our case:
down dking sem1 decrements to make it (1->0)zero and runs the thread tking unlocked to locked state //king works
up dking sem2 increments to make it (0->1) unlock because sem2 waitlist is still empty
down dqueen sem1 decrements to make it (1->0)zero and runs the thread tking unlocked to locked state //queen works
up dqueen sem2 increments to make it (0->1) unlock
*/
int kthread_function(void *data)
{
struct kthr_data *pdata = (struct kthr_data*)data;
while(1)
{
//down operation decrements the counter, if the count is 0 then down operation over the semaphore
//1. blocks the calling kernel thread
//2. Insert it into task structure to the queue of the semaphore
//3. schedule another task
down_interruptible(pdata->sem1); //uninterruptible sleep in sem->wait list when sem1 is zero
printk("%s\n", pdata->name);
mdelay(499);
msleep(1);
up(pdata->sem2);
//if the semaphore wait queue is not empty then it pick a task and make it runnable else increment the counter
//if sem->wait list is empty increment sem->count and leave if sem->count is 0 remove the first waiter structure from the sem queue
if(kthread_should_stop())
break;
}
return 0;
}
struct task_struct *ts;
static int __init kthr_init(void)
{
printk("kthread init called");
//semaphore is an object consists of a counter and a queue of waiting tasks
sema_init(&kingsem, 1); //unlocked state
sema_init(&queensem, 0); //locked state
dking.name = "king";
dqueen.name = "queen";
dking.sem1 = &kingsem;
dking.sem2 = &queensem;
dqueen.sem1 = &queensem;
dqueen.sem2 = &kingsem;
tking = kthread_run(kthread_function, &dking, "king");
tqueen = kthread_run(kthread_function, &dqueen, "queen");
return 0;
}
void __exit kthr_exit(void)
{
printk("tking_stop called");
kthread_stop(tking);
printk("tqueen_stop called");
kthread_stop(tqueen);
}
module_init(kthr_init);
module_exit(kthr_exit);
//output:
//king queen king queen ....
//king queen king queen ....
//why we synchronize to know this just comment down and up lines and see there //will not be any ordered synchronized print statements