2
为什么Linux / BSD中没有通用批处理系统调用?
背景: 系统调用开销比函数调用开销大得多(估计范围为20-100x),这主要是由于上下文从用户空间切换到内核空间再返回。内联函数通常可以节省函数调用开销,并且函数调用比syscall便宜得多。可以说,开发人员希望通过尽可能多地在一个系统调用中进行内核内操作来避免一些系统调用开销。 问题: 这已经创造了很多(多余的?)系统调用像sendmmsg() ,的recvmmsg()还有CHDIR,开放,lseek的和/或类似的符号链接组合:openat,mkdirat,mknodat,fchownat,futimesat,newfstatat,unlinkat,fchdir,ftruncate,fchmod,renameat,linkat,symlinkat,readlinkat,fchmodat,faccessat,lsetxattr,fsetxattr,execveat,lgetxattr,llistxattr,lremovexattr,fremovexattr,flistxattr,fgetxattr,pread,pwrite等... 现在,Linux已添加copy_file_range(),显然将读取lseek和写入syscall组合在一起。变成fcopy_file_range(),lcopy_file_range(),copy_file_rangeat(),fcopy_file_rangeat()和lcopy_file_rangeat()只是时间问题...但是由于涉及2个文件而不是另外X个调用,因此它可能变成X ^ 2更多。好的,Linus和各种BSD开发人员不会放任不管,但我的观点是,如果有一个批处理syscall,那么所有这些(大部分?)都可以在用户空间中实现,并且可以减少内核复杂性而无需增加太多如果libc方面有任何开销。 已经提出了许多复杂的解决方案,其中包括某种形式的特殊syscall线程,用于非阻塞syscall到批处理syscall。但是,这些方法以与libxcb和libX11几乎相同的方式为内核和用户空间增加了相当大的复杂性(异步调用需要更多的设置) 解?: 通用批处理系统调用。这将减轻最大的成本(多模式切换),而不会具有与专用内核线程相关的复杂性(尽管以后可以添加功能)。 socketcall()系统调用中的原型基本上已经有了良好的基础。只需将其从采用参数数组扩展为采用返回数组,指向参数数组的指针(包括系统调用号),系统调用数和标志参数即可,如下所示: batch(void *returns, void *args, long ncalls, long flags); 一个主要的区别是,为了简单起见,参数可能全部都需要用作指针,以便先前的syscall的结果可以被后续的syscall使用(例如open(),read()/中使用的文件描述符write()) 一些可能的优点: 更少的用户空间->内核空间->用户空间切换 可能的编译器开关-fcombine-syscalls尝试自动进行批处理 异步操作的可选标志(返回fd立即观看) 在用户空间中实现将来的组合syscall功能的能力 题: 实现批处理系统调用是否可行? 我是否缺少一些明显的陷阱? 我是否高估了收益? 对我来说,麻烦实施批处理系统调用是否值得(我不在Intel,Google或Redhat工作)? 我之前已经修补了自己的内核,但不愿处理LKML。 历史表明,即使某些东西对“普通”用户(没有git写访问权限的非公司最终用户)广泛有用,它也可能永远不会在上游被接受(unionfs,aufs,cryptodev,tuxonice等)。 参考文献: FlexSC:具有少异常系统调用的灵活系统调用调度 通过专用用户和内核CPU避免系统调用开销