I have written a kernel module that creates a kernel thread in its init method. The kernel thread sleeps until someone calls the module's read method to wake it up and then prints some log messages. I have allowed SIGKILL signal to be deliverable to the thread. But I can't kill the thread with SIGKILL.
My questions are -
1. Why is the thread not receiving SIGKILL even after allowing it? How can I kill the thread before unloading the module?
2. Is there any race condition in the way I am testing the condition to check against spurious signals? Should I use lock before/after access to "condition" variable?
code goes below -
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <asm/signal.h>
#include <linux/wait.h>
#define kthread_debug(fmt, arg...) \
printk(KERN_ALERT fmt, ##arg)
static int kthread_major = 0;
/* declare and initialize wait queue head used for sleeping */
static DECLARE_WAIT_QUEUE_HEAD(mkthread_waitqueue);
static int condition;
rwlock_t mevent_lock;
/* mkthread is the entry point for kernel thread, we don't use argument */
static int
mkthread(void *arg)
{
kthread_debug("mkthread created\n");
try_module_get(THIS_MODULE);
/* declare wait queue entry */
DECLARE_WAITQUEUE(wait, current);
/* all the gunge required to become a kernel thread without
attached user resources in one place where it belongs. */
daemonize("mkthread");
/* since daemonize blocks all signal we enable only SIGKILL here */
allow_signal(SIGKILL);
/* the thread will sleep on this wait queue until it gets woken up */
add_wait_queue(&mkthread_waitqueue, &wait);
for (;;) {
/* guard against spurious wake up */
while (!condition) {
/* must be set before calling schedule() to
* avoid race condition */
set_current_state(TASK_INTERRUPTIBLE);
/* remove current from run queue and schedule a new process */
schedule();
}
/* we wake up here */
/* check for pending SIGKILL signal, die if there is any */
if (signal_pending(current)) {
kthread_debug("SIGKILL pending\n");
break;
}
/* is there a race condition ? */
condition = 0;
kthread_debug("mkthread woke up!\n");
}
/* change task stae to TASK_RUNNING before removing from wait queue */
set_current_state(TASK_RUNNING);
remove_wait_queue(&mkthread_waitqueue, &wait);
module_put(THIS_MODULE);
return 0;
}
static ssize_t
kthread_read(struct file *filp, char *ubuf, size_t count, loff_t *f_pos)
{
condition = 1;
wake_up_interruptible(&mkthread_waitqueue);
return 0;
}
/* the open function is used to create kernel thread */
static int
kthread_open(struct inode* indode, struct file* filp)
{
kthread_debug("kthread_open done\n");
return 0;
}
struct file_operations kthread_ops = {
.owner = THIS_MODULE,
.open = kthread_open,
.read = kthread_read
};
static void
__exit kthread_module_exit(void)
{
kthread_debug("kthread_module_exit done\n");
}
static int
__init kthread_module_init(void)
{
int ret = 0;
ret = register_chrdev(kthread_major, "kthread", &kthread_ops);
if (ret < 0) {
printk(KERN_ERR "register_chrdev() error\n");
}
kthread_major = ret;
kthread_debug("kthread module registered with major: %d\n", kthread_major);
kernel_thread(mkthread, 0, CLONE_KERNEL);
kthread_debug("kthread_module_init done\n");
return ret;
}
module_init(kthread_module_init);
module_exit(kthread_module_exit);
Be a better Heartthrob. Get better relationship answers from someone who knows.
Yahoo! Answers - Check it out.