http://www.vrlinux.com/naheyuanma/20100414/35376.html
关于work_struct与阻塞的问题(很诡异哦~)
发布时间:2010-04-13
[code]mknod my_fifo_w p[/code][code]
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <asm/uaccess.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/irq.h>
struct my_struct_t
{
struct work_struct my_work;
char *filename;
};
struct my_struct_t my_struct;
void file_read(struct work_struct *work)
{
struct file *filp;
struct inode *inode;
mm_segment_t fs;
int fsize;
char *buf;
unsigned long magic;
unsigned long phy_addr;
unsigned long addr_len;
char *filename = my_struct.filename;
printk(KERN_ALERT "start.../n");
filp = filp_open(filename,O_RDONLY,0);
inode = filp->f_dentry->d_inode;
magic = inode->i_sb->s_magic;
printk(KERN_ALERT "file system magic:%li/n",magic);
printk(KERN_ALERT "super blocksize:%li/n",inode->i_sb->s_blocksize);
printk(KERN_ALERT "inode %li/n",inode->i_ino);
// fsize = inode->i_size;
// printk(KERN_ALERT "file size:%i/n",(int)fsize);
fsize = 20;
buf = (char *)kmalloc(fsize+1,GFP_ATOMIC);
phy_addr = virt_to_phys((void *)buf);
printk(KERN_ALERT "the baseaddr is %x/n",phy_addr);
fs = get_fs();
set_fs(KERNEL_DS);
addr_len = filp->f_op->read(filp,buf,fsize,&(filp->f_pos));
printk(KERN_ALERT "the context length is %lu/n",addr_len);
set_fs(fs);
buf[fsize] = '/0';
printk(KERN_ALERT "the file context is /n");
printk(KERN_ALERT "%s/n",buf);
kfree(buf);
filp_close(filp,NULL);
return ;
}
static int file_init(void)
{
char *filename = "/root/thread/pipe/my_fifo_w";
my_struct.filename=filename;
INIT_WORK(&(my_struct.my_work),file_read);
schedule_work(&(my_struct.my_work));
return 0;
}
static void file_exit(void)
{
return ;
}
module_init(file_init);
module_exit(file_exit);
MODULE_LICENSE("GPL");
[/code][code]obj-m :=file.o
modules:
make -C /lib/modules/`uname -r`/build M=`pwd` modules[/code]前几天在论坛上看到一个关于内核中文件读写的帖子,很感兴趣,便仿照着做了几个实验,大部分代码还属于copy。。呵呵
针对于普通文件的读写没有问题,今天看到命名管道的时候,忽然有了新的想法,想针对管道这种特殊文件做一下测试。
管道的两端在以非NONBLOCK的只读(只写)方式打开时会发生阻塞,等待另一方以相对的形式打开文件,这时在加载测试模块的时候由于先回产生阻塞
会令系统模块出现问题,此模块无法被卸载。(若用户空间先打开管道文件,则任何情况都没问题,固不讨论,并且fifo首先已经生成,)。
于是我就想通过一种方式能把能把阻塞的打开工作给推后执行,中断下半部的工作队列正好是适用于此类情况的一种机制,而且工作队列实际上是以内核进程
的方式实现,应该并非只能用于中断中。
我首先写了一段很简短的代码测试模块加载中的工作队列的运行情况,发现可以实现。因此最后出现了上述代码,本意是想让模块加载过程先结束,让工作队列
阻塞在open()函数上,等待用户进程对文件的打开。
但实际加载模块之后出现了极其诡异的现象,整个终端在疯狂的换行,就像有人一直摁回车一样,打开任意终端都是这样,请多次测试发现问题的确有加载的内核
模块所引起,十分的困惑,还望有高人帮忙解答。
是不应该在此使用工作队列的原因吗,还是工作队列阻塞的原因呢?。。。 如果是这样,有没有其他一种方式能让工作任务先不考虑而推后执行吗?(先不考虑即在内核
模块加载的过程中不出现意外)
帖子写的很长,可能问题也表述的不是很清楚,本人刚开始学习Linux内核知识,还请见谅。
估计是在工作队列中睡眠引起的,下半部不允许睡眠。能否lz创建内核线程,然后读文件试试?
工作队列处理函数中不是允许睡眠的吗?
不允许,进程才可以睡眠
我看书上说,工作队列通过内核线程实现,工作在进程上下文中,而软中断和tasklet工作在中断上下文中,所以可以在工作队列中睡眠或阻塞,难道不是这样吗?
是啊,workqueue确实是在内核线程中执行的,那应该可以睡眠的