OS 中的任务是如何启动和停止的?
How is starting and stopping the tasks in OS done?
尝试使用上下文切换进行一些练习,我发现了以下问题:
上下文保存和恢复似乎不是问题,但启动和停止任务似乎有点棘手。
虽然设置任务只是正确设置 PC 寄存器、堆栈指针和一些寄存器,但问题是,当任务结束时,我们无法控制它接下来要做什么(我们不知道return地址)。
我想出了两个解决这个问题的办法:
- 为程序设置 return 地址,告诉 OS 终止、释放与任务相关的内存并从队列中删除任务。
- 将要启动的函数包装到另一个函数中,该函数将指向被调用函数的指针作为参数。
第二个解决方案可能看起来更像以下
void pre_startup(void(*funct)){
funct();
task_end();
}
作为参数,我们将适当的寄存器设置为指向任务的指针。
我的问题是:
OSes 如何处理所描述的问题?他们使用上述解决方案之一还是有一些不同的方法可以更好地处理这个问题?
他们使用内存控制器来移动内存 - 这会交换整个内存部分,包括所有堆、堆栈和可执行文件,恢复寄存器、程序计数器、堆栈指针。等见:
What is a context switch?
在大多数平台上,C 运行时中的启动函数将在 main()
returns 之后调用 exit()
,例如
void _start(int argc, char **argv, char **envp) {
// call initializers...
int r = main(argc, argv, envp);
// call finalizers...
exit(r);
}
这都是系统特定的,但在较高级别,您可以通过以下方式实现 exit () 或其等效项:
- 正在进入内核模式退出处理程序。
- 调用调度程序并执行上下文切换到新进程。
- 执行必要的处理以删除第一个进程。
- Return 来自新进程中的异常。
尝试使用上下文切换进行一些练习,我发现了以下问题:
上下文保存和恢复似乎不是问题,但启动和停止任务似乎有点棘手。
虽然设置任务只是正确设置 PC 寄存器、堆栈指针和一些寄存器,但问题是,当任务结束时,我们无法控制它接下来要做什么(我们不知道return地址)。
我想出了两个解决这个问题的办法:
- 为程序设置 return 地址,告诉 OS 终止、释放与任务相关的内存并从队列中删除任务。
- 将要启动的函数包装到另一个函数中,该函数将指向被调用函数的指针作为参数。
第二个解决方案可能看起来更像以下
void pre_startup(void(*funct)){
funct();
task_end();
}
作为参数,我们将适当的寄存器设置为指向任务的指针。
我的问题是:
OSes 如何处理所描述的问题?他们使用上述解决方案之一还是有一些不同的方法可以更好地处理这个问题?
他们使用内存控制器来移动内存 - 这会交换整个内存部分,包括所有堆、堆栈和可执行文件,恢复寄存器、程序计数器、堆栈指针。等见:
What is a context switch?
在大多数平台上,C 运行时中的启动函数将在 main()
returns 之后调用 exit()
,例如
void _start(int argc, char **argv, char **envp) {
// call initializers...
int r = main(argc, argv, envp);
// call finalizers...
exit(r);
}
这都是系统特定的,但在较高级别,您可以通过以下方式实现 exit () 或其等效项:
- 正在进入内核模式退出处理程序。
- 调用调度程序并执行上下文切换到新进程。
- 执行必要的处理以删除第一个进程。
- Return 来自新进程中的异常。