Hi

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. 

Reply via email to