我们在使用系统调用的时候(在用户级),从来不放sys_前缀,但是为什么我们在调用系统调用函数的时候,首先调用的是系统调用处理函数(前缀为sys_),这里我们调用的是sleep函数,但是它进入了sys_sleep()函数,然后进入了主sleep()函数呢:例如在用户级程序中:
int main(int argc,char* argv[])
{
sleep(2);
return 0
}
这里我们调用了sleep函数,但是它先进入**sys_sleep()**函数,然后进入主sleep函数。
int
sys_sleep(void)
{
int n;
uint ticks0;
if(argint(0, &n) < 0)
return -1;
acquire(&tickslock);
ticks0 = ticks;
while(ticks - ticks0 < n){
if(myproc()->killed){
release(&tickslock);
return -1;
}
sleep(&ticks, &tickslock); //Here the main sleep() function is called.
}
release(&tickslock);
return 0;
}
我们没有在*用户级程序*中编写callsys_sleep(),但是它首先进入那里,然后调用主**sleep()**函数。
2条答案
按热度按时间b1uwtaje1#
sleep()函数是一个标准库函数,通常在unistd. h中找到。标准库中的大多数函数都是通过提供链接到可执行文件的共享库来实现的。此共享库中的函数将使用系统调用来请求操作系统内核提供与您调用的函数相关的服务。
函数本身的名字经常用宏来掩盖。
您正在从代码中调用sleep,但编译器会将每次出现的sleep替换为sys_sleep。共享库本身并不是系统调用。共享库是一个 Package 器,用于简化系统调用并模块化编译器。只要您不调用共享库并将其与代码链接,编译器就不会干涉系统调用。当您这样做时,共享库包含以下代码
第一条指令将syscall号放入一个寄存器中并执行syscall,这使得处理器在 Boot 时跳转到OS设置的syscall处理程序。处理程序会查看rax并打开值以确定它正在处理的syscall。为了帮助您理解,我做了一个小Linux示例:
创建以下3个文件:
main.c
shared.c
shared.h
现在运行以下命令:
您应看到类似以下内容:
现在,您可以键入
layout asm
并按Enter键,以便在单步执行时查看程序集。键入si
,然后重复按Enter键,以获得单步执行指令。您将看到,您获得的结果与睡眠时类似()系统调用。这正是标准库实现所做的事情,只是共享库将与小的程序集片段(如包含指令syscall
。kcwpcxri2#
sleep
在user.h中被声明。sleep
在usys.S中定义:让我们看看:
将会在
发生了什么事?
当调用(用户)函数
sleep
时%eax
设置为SYS_sleep
(其值为13(参见syscall.h),SYS_sleep
在sysproc.c中定义T_SYSCALL
(64参见traps.h)升高。sleep
也返回。sys_sleep
调用的sleep
定义位于proc.c中,只能从内核模式访问