在某些代码中,我可以看到以奇怪的方式调用系统调用,以sched_yield
为例:
#define __NR_sys_sched_yield __NR_sched_yield
inline _syscall0(void, sys_sched_yield);
然后我们可以使用sys_sched_yield()
。
我很好奇直接使用sched_yield
和这种方式之间的区别。
在src / include / asm / unistd中,定义了_syscall0
:
#define _syscall0(type,name) \
type name(void) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name)); \
__syscall_return(type,__res); \
}
答案 0 :(得分:0)
可能是那些可能无法使用Song ID
的系统。
至于差异,=INDEX('worksheet 1'!A:A,MATCH("*"&B5&"*",'worksheet 1'!D:D,0))
会在出错时返回sched_yield
并设置sched_yield
,而此实现可能会从内核返回原始值。无法确定,因为您没有提供必须是宏的-1
的定义。
答案 1 :(得分:0)
这是使用glibc的linux。 BSD有一个sched_yield但有自己的libc。
这并不奇怪。 syscall0宏发出汇编int 0x80
指令,并且系统调用号位于rax
寄存器[x86架构]中。这是linux的标准系统调用接口。在幕后,所有作为系统调用包装器的linux glibc函数都会这样做[或使用更现代的sysenter / sysexit x86指令配对]
glibc倾向于在其包装函数中“篡夺”系统调用并添加它们周围的东西。例如,当你调用fork
时,它[最终]调用__libc_fork
,它会执行大量与线程和文件关闭等相关的额外内容。
一般来说,glibc做出了不错的选择。但是,有时经验丰富的Linux应用程序程序员希望原始系统调用行为,特别是如果他们正在编写必须与内核,设备驱动程序或设备硬件进行密切交互的系统实用程序或程序/库。 / p>
实际上,__libc_fork
不会调用fork
系统调用,而是调用clone
系统调用,这是[更难使用] fork
的超集。但是,普通的fork
系统调用仍然存在。所以,如果你想要那个,你需要宏观的东西 - 我敢打赌某处有一个sys_fork
定义。
另一方面,glibc可能会将sched_yield
ala POSIX实现为nop,返回-1并将errno设置为ENOSYS
。我刚检查了最新的glibc源代码,除了mach之外我找不到“真正的”实现。它可能确实做了真实的事情,我找不到它。
有时候,linux有一个系统调用,但是glibc不想支持它,或者他们认为它对于应用程序程序员来说太危险了,所以他们忽略了包装函数。因此,宏是一种“结束”glibc的方式。
glibc实施sched_yield
作为nop(posix)的可能原因是他们认为它“不好”并且可能会告诉您使用nanosleep
代替。我已经使用了它们,它们不相同,具体取决于您的用例和所需效果。
有时,您需要执行原始的内联系统调用。例如,内核调用ELF加载器[每个支持ELF二进制文件的系统必须有一个并且linux是ld-linux.so
]来加载ELF二进制文件。它必须在glibc.so可用之前运行,因为它实际上是glibc.so中的链接,ELF加载器必须有一些内置的系统调用open
和read
此外,大多数系统都有一个syscall
库函数,它接受可变数量的参数。你可以实现:
#define my_sched_yield() syscall(__NR_sched_yield)
#define my_read(_fd,_buf,_len) syscall(__NR_read,_fd,_buf,_len)
此函数处理内核的系统调用返回值/错误并设置errno。这就是__syscall_return
宏必须做的事情。
__NR_*
前缀是linux使用的,但其他系统有AUE_*
或SYS_*