/* * wakeup_test.c -- Linux kernel invalid wake up problem simulation test module * * Written By: Libin * * History * ------- */ #include #include #include #include #include #include #include #include #include #define NAME "wakeup_test" #define WAIT_TIMEOUT HZ*30 static LIST_HEAD(product_list); struct product_struct{ int data; struct list_head list; }; static struct task_struct *producer, *consumer; static struct completion done; static int producer_thread(void *unused) { struct product_struct *product; product = (struct product_struct *)kmalloc(sizeof (struct product_struct), GFP_KERNEL); product->data = 1; list_add_tail(&product->list, &product_list); wake_up_process(consumer); printk(KERN_INFO "%s: kthread producer try to wake up the kthread consumer\n", NAME); complete(&done); /* NOTE: added for problem trigger simulation */ while (!kthread_should_stop()){ set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); } printk(KERN_INFO "%s: kthread producer exit\n", NAME); return 0; } static void simulate_preempted(void) { schedule(); } static void wakeup_wait_timeout(unsigned long unused) { printk(KERN_ERR "%s: kthread consumer have waited for %ds, " "indicating trigger an invalid wakeup problem!\n", NAME, WAIT_TIMEOUT/HZ); } static int consumer_thread(void *unused) { struct timer_list wakeup_wait_timer; setup_timer(&wakeup_wait_timer, wakeup_wait_timeout, (unsigned long)NULL); wait_for_completion(&done); /* NOTE: added for problem trigger simulation */ mod_timer(&wakeup_wait_timer, jiffies + WAIT_TIMEOUT); set_current_state(TASK_INTERRUPTIBLE); simulate_preempted(); /* NOTE: added for problem trigger simulation */ while (list_empty(&product_list)){ schedule(); set_current_state(TASK_INTERRUPTIBLE); } __set_current_state(TASK_RUNNING); del_timer_sync(&wakeup_wait_timer); if (kthread_should_stop()){ goto out; } if (!list_empty(&product_list)){ printk(KERN_INFO "%s: kthread consumer be woken up successfully, all right!\n", NAME); } while (!kthread_should_stop()){ set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); } out: printk(KERN_INFO "%s: kthread consumer exit\n", NAME); return 0; } static int __init wakeup_test_init(void) { producer = kthread_create(producer_thread, NULL, "producer"); consumer = kthread_create(consumer_thread, NULL, "consumer"); init_completion(&done); wake_up_process(producer); wake_up_process(consumer); printk(KERN_INFO "%s: create two kernel threads - producer & consumer\n", NAME); printk(KERN_INFO "%s: module loaded successfully\n", NAME); return 0; } static void __exit wakeup_test_exit(void) { kthread_stop(producer); kthread_stop(consumer); printk(KERN_INFO "%s: module unloaded successfully\n", NAME); } module_init(wakeup_test_init); module_exit(wakeup_test_exit); MODULE_LICENSE("GPL");