微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 内核等待队列机制介绍

内核等待队列机制介绍

时间:02-25 来源:互联网 点击:

除掉。相对应的,在 buf_release() 中,我们应该要将 use count 减一。就像开启档案一样。有 open(),就应该要有对应的 close() 才行。如果 module 的 use count 在不为 0 的话,那此 module 就无法从 kernel 中移除了。

static int buf_release( struct inode *inode,struct file *filp )
{
MOD_DEC_USE_COUNT;
return 0;
}

接下来,我们要看一下buf_read()和buf_write()。

static ssize_t buf_read( struct file *filp,char *buf,size_t count,
loff_t *ppos )
{
return count;
}

static ssize_t buf_write( struct file *filp,const char *buf,
size_t count,loff_t *ppos )
{
return count;
}

在此,我们都只是回传 user 要求读取或写入的字符数目而已。在此,我要说明一下这些参数的意义。filp 是一个 file 结构的 pointer。也就是指我们在 /dev 下所产生的 buf 档案的 file 结构。当我们呼叫 read() 或 write() 时,必须要给一个 buffer 以及要读写的长度。Buf 指的就是这个 buffer,而 count 指的就是长度。至于 ppos 是表示目前这个档案的 offset 在那里。这个值对普通档案是有用的。也就是跟 lseek() 有关系。由于在这里是一个 drvice。所以 ppos 在此并不会用到。有一点要小心的是,上面参数 buf 是一个地址,而且还是一个 user space 的地址,当 kernel 呼叫 buf_read() 时,程序在位于 kernel space。所以你不能直接读写资料到 buf 里。必须先切换 FS 这个 register 才行。

Makefile
P = buf
OBJ = buf.o
INCLUDE = -I/usr/src/linux/include/linux
CFLAGS = -D__KERNEL__ -DMODVERSIONS -DEXPORT_SYMTAB -O $(INCLUDE) \
-include /usr/src/linux/include/linux/modversions.h
CC = gcc

$(P): $(OBJ)
ld -r $(OBJ) -o $(P).o

.c.o:
$(CC) -c $(CFLAGS) $

clean:
rm -f *.o *~ $(P)

加入上面这个 Makefile,打入 make 之后,就会产生一个 buf.o 的档案。利用 insmod 将 buf.o 载到 kernel 里。相信大家应该都用过 /dev/zero 这个 device。去读取这个 device,只会得到空的内容。写资料到这个 device 里也只会石沈大海。现在你可以去比较 buf 和 zero 这两个 device。两者的行为应该很类似才是。

第三步,我们在第二步中 implement 一个像 zero 的 device driver。我们现在要经由修改它来使用 wait_queue。首先,我们先加入一个 global variable,write_wq,并把它设为 NULL。

struct wait_queue *write_wq = NULL;

然后,在 buf_read() 里,我们要改写成这个样子。

static ssize_t buf_read( struct file *filp,char *buf,size_t count,
loff_t *ppos )
{
int num,nRead;
nRead = 0;
while ( ( wp == rp ) !flag ) { /* buffer is empty */
return 0;
}

repeate_reading:
if ( rp wp ) {
num = min( count,( int ) ( wp-rp ) );
}
else {
num = min( count,( int ) ( buffer BUF_LEN-rp ) );
}
copy_to_user( buf,rp,num );
rp = num;
count -= num;
nRead = num;
if ( rp == ( buffer BUF_LEN ) )
rp = buffer;
if ( ( rp != wp ) ( count > 0 ) )
goto repeate_reading;
flag = 0;
wake_up_interruptible( write_wq );
return nRead;
}

在前头我有提到,buf 的地址是属于 user space 的。在 kernel space 中,你不能像普通写到 buffer 里一样直接将资料写到 buf 里,或直接从 buf 里读资料。Linux 里使用 FS 这个 register 来当作 kernel space 和 user space 的切换。所以,如果你想手动的话,可以这样做:

mm_segment_t fs;
fs = get_fs();
set_fs( USER_DS );
write_data_to_buf( buf );
set_fs( fs );

也就是先切换到 user space,再写资料到 buf 里。之后记得要切换回来 kernel space。这种自己动手的方法比较麻烦,所以 Linux 提供了几个 function,可以让我们直接在不同的 space 之间做资料的搬移。诚如各位所见,copy_to_user() 就是其中一个。

copy_to_user( to,from,n );
copy_from_user( to,from,n );

顾名思义,copy_to_user() 就是将资料 copy 到 user space 的 buffer 里,也就是从 to 写到 from,n 为要 copy 的 byte 数。相同的,copy_from_user() 就是将资料从 user space 的 from copy 到位于 kernel 的 to 里,长度是 n bytes。在以前的 kernel 里,这两个 function 的前身是 memcpy_tofs() 和 memcpy_fromfs(),不知道为什么到了 kernel 2.2.1之后,名字就被改掉了。至

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top