微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

带有等待队列挂起系统的Linux驱动程序代码

我写了一个示例linux设备驱动程序代码,它将创build两个内核线程,每个线程将增加一个全局variables。 我使用了等待队列来执行递增variables的任务,每个线程将等待等待队列,直到一个定时器到期,每个线程随机唤醒。

但问题是当我插入这个模块,整个系统只是冻结了,我不得不重新启动机器。 每次插入模块时都会发生这种情况。 我试着debuggingkthread代码,看看我是否进入了死锁的情况,但我无法弄清楚代码有什么问题。

任何人都可以告诉我我在做什么错误代码获取挂断的情况?

#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() %ldn",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=%dn",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,&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 Failedn"); return -1; } printk(KERN_INFO "starting the second kernel thread with id"); kthread_pid2 = kthread_run(kthread_routine_2,"second_kthread"); printk(KERN_INFO "%ld n",(long)kthread_pid2); if(kthread_pid2 < 0 ){ printk(KERN_ALERT "Kernel thread [2] creation Failedn"); 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_timern"); 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");

了解read()和write()的行为

Windows 8应用程序WebView捕获事件目标=“_ blank”

Windows 10 UWP – 如果前台应用正在运行,则停止后台任务

C#/ .net:报告subprocess状态到父服务

如何停止gSOAP操作

从StackPanel中删除除第一个以外的所有项目?

什么是在C中的结构的实际大小

rawsocket sendto()的一些数据包被丢弃,在networking中看不到

如何绑定一个jpg文件一个exe文件,产生一个“exe”文件

获取ram制造商

您需要在两个线程函数调用schedule() :

/* In kernel thread function... */ set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&wqueue,&wait); schedule(); /* Add this call here */ spin_lock_irqsave(&my_si_lock,flags); /* etc... */

调用set_current_state(TASK_INTERRUPTIBLE)设置当前进程任务结构中的状态,一旦进入休眠状态,调度程序就可以将进程从运行队列中移出。 但是你必须告诉调度员,“好吧,我已经设定了一个新的状态,现在重新安排我。” 您错过了第二步,所以更改的标志在下一次调度程序决定暂停您的线程时才会生效,并且无法知道将要发生多久,或者您的代码正在执行的哪一行它发生(除了在锁定的代码 – 不应该被打断)。

我不确定为什么它会导致整个系统锁死,因为你的系统状态是相当不可预测的。 由于内核线程并没有等待计时器在获取锁和循环之前过期,我不知道什么时候可以期望调度器对新的任务结构状态进行实际的操作,并且很多事情可能发生在与此同时。 你的线程反复调用add_wait_queue(&wqueue,&wait); 和remove_wait_queue(&wqueue,&wait); ,所以在定时器回调触发时,谁知道等待队列处于什么状态。 事实上,由于内核线程正在旋转,所以这段代码一个竞争条件:

if (waitqueue_active(&wqueue)) { wake_up_interruptible(&wqueue); }

当执行if语句时,有可能在waitqueue上有活动的任务,只是在wake_up_interruptible(&wqueue);的时候才让它们清空wake_up_interruptible(&wqueue); 叫做。

顺便说一句,我假设你目前增加一个全局变量的目标只是一个学习waitqueues和睡眠状态的练习。 如果你想要实际上实现一个共享计数器,而不是看原子操作 ,你将能够转储自旋锁。

如果您决定保留自旋锁,则应改用DEFINE_SPINLOCK()宏。

另外,正如我在我的评论中提到的,你应该把你的两个kthread_pid变量改为task_struct *类型。 你还需要调用kthread_stop(kthread_pid); 在你开始的每个线程的__exit例程中。 如果你不告诉他们停止, kthread_should_stop()将永远不会返回true。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐