I have two kernel threads and I am trying to print from these two threads in alternate fashion. I am using spinlock to sync these two threads.
int kthread_1_function(void *data)
{
while(1)
{
spin_lock(&lock1);
pr_alert("In Kernel Thread 1!!!\n");
spin_unlock(&lock2);
if(kthread_should_stop())
{
spin_unlock(&lock2);
return 1;
}
}
return 0;
}
int kthread_2_function(void *data)
{
while(1)
{
spin_lock(&lock2);
pr_alert("In Kernel Thread 2!!!\n");
spin_unlock(&lock1);
if(kthread_should_stop())
{
spin_unlock(&lock1);
return 2;
}
}
return 0;
}
In init module, I create these kernel threads (kthread_run) and cleanup_module stop these threads (kthread_stop).
When I try to remove the module entire system hangs. By browsing the kernel source I could see that spin_lock disables preemption and kthread_stop tries to wake up the thread which is supposed to be killed and waits for the thread to exit and return. Not sure what is making my system hang. Logically speaking it should have worked fine.
Note: When I initialize the spinlocks, I set lock1 as UNLOCKED and lock2 as LOCKED.
You have a double unlock problem here. Spinlock in linux is implemented using a mechanism called "spinlock ticketing". If you unlock a spinlock twice under this scheme every other attempt to lock the spin lock will cause the thread to spin forever.
So the issue is that if(kthread_should_stop()) is true, you unlock the lock twice, getting all the other threads trying to fetch it stuck.
More about spinlock ticketing: http://en.wikipedia.org/wiki/Ticket_lock
Also note that using the two locks is somewhat obsolete. I would just share one lock between the 2 threads.
Well, you just hinted the solution: in spinlock(), preemption is disabled. so in spin_unlock(), it is reenabled back.
Now, problem is you have spin_unlocked on a different variable than before, and immediately upon spin_unlocked, preemption enabled, and normal CPU scheduling will then schedule the kernel threads to another CPU to continue the execution.
And since you have created two kthread, each of them can be schedule by the kernel independently. So you will end up one kthread blocking on another kthread, each running on different CPU.
The spin lock concept has been created due to the existence of multicore: in single core, no spin lock is needed: why should the CPU do nothing but spinning on a lock waiting for it to be unfree, when there is only one CPU?
It is preferred that you unlock on spin lock before locking on another, because each spin lock can be running on a different CPU itself, as CPU scheduling is really out of your control.