由 __up() 函数中最后执行了wake_up_process() 唤醒另外一个进程,所以globalvar_write()函数中在up()后面的语句都没有执行,于是flag的值还是为0,当然globalvar_write()后面的打印语句也不会执行。当唤醒正在操作globalvar_read()函数的进程之后,globalvar_read()开始执行,globalvar_read() 立刻持有信号量sem,由于此时flag的值为0,wait_event_interruptible()将导致进程进入睡眠,此时就产生了死锁——该进程持有信号量睡眠后将不能释放该信号量。就会导致globalvar_write()函数得不到执行,自然flag的值也不会变为1,globalvar_read()也不会醒,因此产生了死锁。(后面会有文章介绍wait_event_interruptible的原理)
注意到list_first_entry()这个函数可以获得链表的第一个元素,在内核中这是非常经典的一个东东,分析内核必会。后面还会专门介绍内核中的list.
下面给出应用程序:
首先是globalvar_read.c
#include
#include
#include
#include
int main()
{
int fd, num;
fd = open("/dev/CDEV_ZHU", O_RDWR, S_IRUSR | S_IWUSR);
if (fd != - 1)
{
while (1)
{
read(fd, &num, sizeof(int)); //程序将阻塞在此语句,除非有针对 globalvar 的输入
printf("The globalvar is %d\n", num);
//如果输入是 0,则退出
if (num == 0)
{
close(fd);
break; }
}
}
else
{
printf("device open failure\n");
}
return 0;
}
然后是globalvar_write.c
#include
#include
#include
#include
int main()
{
int fd, num;
fd = open("/dev/CDEV_ZHU", O_RDWR, S_IRUSR | S_IWUSR);
if (fd != -1)
{
while (1)
{
printf("Please input the globalvar:\n");
scanf("%d", &num);
write(fd, &num, sizeof(int));
//如果输入 0,退出
if (num == 0)
{
close(fd);
break;
}
}
}
else
{
printf("device open failure\n");
}
return 0;
}
使用这两个程序可以互斥的对驱动程序中的globalvar进行读写,但是注意驱动中globalvar_read()函数中,代码需要改为先wait_event_interruptible 再 down_interruptible()。