Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 为什么在Linux字符驱动程序读取调用中大小总是=4096?_C_Linux_Linux Kernel_Linux Device Driver - Fatal编程技术网

C 为什么在Linux字符驱动程序读取调用中大小总是=4096?

C 为什么在Linux字符驱动程序读取调用中大小总是=4096?,c,linux,linux-kernel,linux-device-driver,C,Linux,Linux Kernel,Linux Device Driver,我一直在网上浏览Linux字符驱动程序示例,但遇到了一个无法解释的行为 static ssize_t my_read(struct file *f, char __user *user_buf, size_t cnt, loff_t* off) { printk( KERN_INFO "Read called for %zd bytes\n", cnt ); return cnt; } 该消息始终指示cnt=4096字节,无论用户空间中指定的字节数是多少(例如: 但是,用户空间读取

我一直在网上浏览Linux字符驱动程序示例,但遇到了一个无法解释的行为

static ssize_t my_read(struct file *f, char __user *user_buf, size_t cnt, loff_t* off)
{
   printk( KERN_INFO "Read called for %zd bytes\n", cnt );
   return cnt;
}
该消息始终指示
cnt=4096
字节,无论用户空间中指定的字节数是多少(例如:

但是,用户空间读取调用

retval = fread(_rx_buffer, sizeof(char), 5, file_ptr);
printf( "fread returned %d bytes\n", retval );
用户空间的输出是

fread returned 5 bytes.
为什么
my_read
中的大小值始终为4096,而
fread
中的值指示为5?我知道我遗漏了一些东西,但不确定是什么…

试试(在
unistd.h
中),它应该输出5个字符。当使用libc(,
fwrite(3)
等),您使用的是内部libc缓冲区,通常为页面大小(几乎总是4kib)

我相信第一次调用
fread()
5字节时,libc会执行4096字节的内部
read()
,下面是
fread()
将只返回libc在与您使用的
文件
结构相关联的缓冲区中已经存在的字节。直到达到4096。第4097个字节将发出另一个4096字节的
读取
,依此类推

当您编写时也会发生这种情况,例如使用
printf()
,它只是
fprintf()
,第一个参数是
stdout()
。libc不会直接调用
write(2)
,而是将您的内容放在其内部缓冲区中(也是4096字节)。如果您调用它,它将刷新

fflush(stdout);
您自己或任何时候它在发送的字节中找到字节0x0a(ASCII换行符)

试试看,你会发现:

#包括/*用于printf()*/
#包括/*用于睡眠()*/
内部主(空){
printf(“以下消息将不会显示\n”);
printf(“你好,世界!”);
睡眠(3);
printf(“\n直到现在…\n”);
返回0;
}
但是,这将起作用(不使用libc的缓冲):

#包括/*用于printf()*/
#包括/*用于sleep()、write()和STDOUT\u文件号*/
内部主(空){
printf(“将显示以下消息\n”);
写(STDOUT_FILENO,“hello!”,6);
睡眠(3);
printf(“见?\n”);
返回0;
}
STDOUT\u FILENO
是标准输出(1)的默认文件描述符

每次有换行符时进行刷新对于终端用户立即查看消息是必不可少的,而且对于每行处理也是很有帮助的,这在Unix环境中经常进行

因此,即使libc直接使用
read()
write()
系统调用来填充和刷新其缓冲区(顺便说一句,C标准库的Microsoft实现必须使用Windows stuff,可能还有
WriteFile
),这些系统调用绝对不知道libc。这会导致在同时使用这两种方法时出现有趣的行为:

#包括/*用于printf()*/
#包括/*for write()和标准输出文件号*/
内部主(空){
printf(“1.第一条消息(立即刷新)\n”);
printf(“2.第二条消息(无刷新)”;
写(STDOUT_FILENO,“3.第三条消息(立即刷新)”,30);
printf(“\n”);
返回0;
}
哪些产出:

1. first message (flushed now)
3. third message (flushed now)2. second message (without flushing)
(第三个在第二个之前!)

另外,请注意,您可以使用关闭libc的缓冲。例如:

#包括/*用于setvbuf()和printf()*/
#包括/*用于睡眠()*/
内部主(空){
setvbuf(标准输出,空,0);
printf(“将显示以下消息\n”);
printf(“你好!”);
睡眠(3);
printf(“见?\n”);
返回0;
}
我从未尝试过,但我想当
fopen()
对字符设备进行加密并禁用此设备的I/O缓冲时,您也可以对
文件*
执行同样的操作:

FILE*fh=fopen(“/dev/my char device”,“rb”);
setvbuf(fh,NULL,_IONBF,0);

这是否可以预读到具有页面粒度的中间缓冲区(4096是CPU配置中广泛使用的页面大小),或者硬盘的块大小(512用于较旧的,4096用于较新的多TB驱动器)?你试过调用9345字节时会发生什么吗?看起来是这样的。如果我通过用户空间请求10、20或4096字节,我会在日志文件中看到“读取调用4096字节”。如果我通过用户空间请求4097字节,我会看到两个新条目“读取调用4096字节”请求9345将导致日志文件中的两个条目,“读取调用8192字节”和“读取调用4096字节”.1-但是
write
是否保证为
printf
刷新libc缓冲区?我一直认为它直接进入内核syscall,但我在规范中找不到任何有关行为的信息。
write
不知道libc。我将在回答中添加一个示例来说明这一点。我认为它必须有som这与缓冲有关,但不了解发生这种情况的原因(更具体地说,是如何能够请求特定的字节数)。非常好的解释!谢谢。
write(0,“hello!”,6);
写入标准输入,而不是标准输出。
STDOUT\u FILENO
为1。
1. first message (flushed now)
3. third message (flushed now)2. second message (without flushing)