strace
非空 stdin的输出:
execve("./cat", ["./cat"], 0x7fff610af090 /* 37 vars */) = 0
sendfile(1, 0, NULL, 1048576) = 4
sendfile(1, 0, NULL, 1048576) = 0
close(0) = 0
exit(0) = ?
+++ exited with 0 +++
strace
空标准输入的输出:
execve("./cat", ["./cat"], 0x7fff610af090 /* 37 vars */) = 0
sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument)
...
uname -a
:5.3.8-arch1-1 #1 SMP PREEMPT @1572357769 x86_64 GNU/Linux
答案1
这似乎是sendfile
通话的预期行为。让我引用 Linus Torvalds 的话:
sendfile() 故意仅适用于使用页面缓存的内容。 EINVAL 基本上是 sendfile 的表达方式:“我会依靠执行读+写操作,所以您最好自己在用户空间中执行此操作,因为这样实际上可能会更有效”。
(https://yarchive.net/comp/linux/sendfile.html)
因此,sendfile
只有stdin
当内核知道这stdin
是实际上一个文件,而不是管道、块设备或其他任何东西。
我自己写了一个简单的程序来检查一下:
#include <stdio.h>
#include <sys/sendfile.h>
int main() {
sendfile(fileno(stdout), fileno(stdin), NULL, 8);
perror("sendfile failed");
}
使用各种重定向运行它清楚地表明,sendfile
只有当输入直接绑定到常规文件(无论是否为空)时,调用才会成功:
$ ./sendfile-test
sendfile failed: Invalid argument
$ ./sendfile-test < empty.txt
sendfile failed: Success
$ ./sendfile-test < non-empty.txt
(...)
sendfile failed: Success
$ ./sendfile-test < /dev/null
sendfile failed: Invalid argument
$ cat empty.txt | ./sendfile-test
sendfile failed: Invalid argument
$ cat non-empty.txt | ./sendfile-test
sendfile failed: Invalid argument
$ cat /dev/null | ./sendfile-test
sendfile failed: Invalid argument