我已经写了一个示例linux设备驱动程序代码,它将创建两个内核线程,每个线程将增加一个全局变量。我使用等待队列来执行递增变量的任务,并且每个线程将等待等待队列,直到定时器到期并且每个线程随机唤醒。带等待队列挂起系统的Linux驱动程序代码
但问题是当我插入这个模块,整个系统刚刚冻结,我必须重新启动机器。每次插入模块时都会发生这种情况。我试着调试kthread代码,看看我是否错误地进入了死锁状态,但我无法弄清楚代码有什么问题。
任何人都可以告诉我我在做什么错误的代码来获取挂断情况?
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/semaphore.h>
#include <linux/wait.h>
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/kthread.h>
spinlock_t my_si_lock;
pid_t kthread_pid1;
pid_t kthread_pid2 ;
static DECLARE_WAIT_QUEUE_HEAD(wqueue);
static struct timer_list my_timer;
int kthread_num;
/* the timer callback */
void my_timer_callback(unsigned long data){
printk(KERN_INFO "my_timer_callback called (%ld).\n", jiffies);
if (waitqueue_active(&wqueue)) {
wake_up_interruptible(&wqueue);
}
}
/*Routine for the first thread */
static int kthread_routine_1(void *kthread_num)
{
//int num=(int)(*(int*)kthread_num);
int *num=(int *)kthread_num;
char kthread_name[15];
unsigned long flags;
DECLARE_WAITQUEUE(wait, current);
printk(KERN_INFO "Inside daemon_routine() %ld\n",current->pid);
allow_signal(SIGKILL);
allow_signal(SIGTERM);
do{
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&wqueue, &wait);
spin_lock_irqsave(&my_si_lock, flags);
printk(KERN_INFO "kernel_daemon [%d] incrementing the shared data=%d\n",current->pid,(*num)++);
spin_unlock_irqrestore(&my_si_lock, flags);
remove_wait_queue(&wqueue, &wait);
if (kthread_should_stop()) {
break;
}
}while(!signal_pending(current));
set_current_state(TASK_RUNNING);
return 0;
}
/*Routine for the second thread */
static int kthread_routine_2(void *kthread_num)
{
//int num=(int)(*(int*)kthread_num);
int *num=(int *)kthread_num;
char kthread_name[15];
unsigned long flags;
DECLARE_WAITQUEUE(wait, current);
printk(KERN_INFO "Inside daemon_routine() %ld\n",current->pid);
allow_signal(SIGKILL);
allow_signal(SIGTERM);
do{
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&wqueue, &wait);
spin_lock_irqsave(&my_si_lock, flags);
printk(KERN_INFO "kernel_daemon [%d] incrementing the shared data=%d\n",current->pid,(*num)++);
spin_unlock_irqrestore(&my_si_lock, flags);
remove_wait_queue(&wqueue, &wait);
if (kthread_should_stop()) {
break;
}
}while(!signal_pending(current));
set_current_state(TASK_RUNNING);
return 0;
}
static int __init signalexample_module_init(void)
{
int ret;
spin_lock_init(&my_si_lock);
init_waitqueue_head(&wqueue);
kthread_num=1;
printk(KERN_INFO "starting the first kernel thread with id ");
kthread_pid1 = kthread_run(kthread_routine_1,&kthread_num,"first_kthread");
printk(KERN_INFO "%ld \n",(long)kthread_pid1);
if(kthread_pid1< 0){
printk(KERN_ALERT "Kernel thread [1] creation failed\n");
return -1;
}
printk(KERN_INFO "starting the second kernel thread with id");
kthread_pid2 = kthread_run(kthread_routine_2,&kthread_num,"second_kthread");
printk(KERN_INFO "%ld \n",(long)kthread_pid2);
if(kthread_pid2 < 0){
printk(KERN_ALERT "Kernel thread [2] creation failed\n");
return -1;
}
setup_timer(&my_timer, my_timer_callback, 0);
ret = mod_timer(&my_timer, jiffies + msecs_to_jiffies(2000));
if (ret) {
printk("Error in mod_timer\n");
return -EINVAL;
}
return 0;
}
static void __exit signalexample_module_exit(void)
{
del_timer(&my_timer);
}
module_init(signalexample_module_init);
module_exit(signalexample_module_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Demonstrates use of kthread");
如果你想让人们学习你的内核代码,那么至少要使用内核编码风格来提高可读性。 – sawdust 2014-10-07 18:45:49
尝试打开第二个终端窗口并在加载模块时在该窗口中使用“tail -f”。您的系统仍会锁定,但您可能会看到一些printk调用在系统日志之前被附加到系统日志中。另外,我怀疑这是你的问题,但将你的kthread_pid变量改为'struct task_struct *'数据类型。调用kthread_run与用户空间中的fork()不同,它[返回不同的数据类型](http://lxr.free-electrons.com/source/include/linux/kthread.h#L22)。 –
skrrgwasme
2014-10-07 19:30:32