4

我有一个关于 Linux 的深度工作的问题。

假设一个多线程进程正在 CPU 中执行。在这种情况下,我们将有一个正在 CPU 上执行的线程。在更广泛的情况下,我们会将属于进程的相应页面加载到 RAM 中以供执行。

假设线程进行系统调用。我对这之后的工作有点不清楚。中断将产生一个调用。我的一个问题是谁来接听这个电话?

假设系统有 m:n 个用户级线程到内核级线程的映射,我假设相应的内核级线程会响应这个调用。

因此内核将查找中断向量表并获取需要执行的例程。我的下一个问题是执行中断时将使用哪个堆栈?是内核线程的堆栈还是用户级线程的堆栈?(我假设它将是内核线程的堆栈。)

回到程序流程,假设操作是使用fopen. 我的下一个问题是如何从 ISR 跳转到系统调用?或者我们的 ISR 是否映射到系统调用?

同样在更广泛的情况下,当内核线程正在执行时,我假设 RAM 上的“OS 区域”将用于容纳正在执行系统调用的页面。

再次从不同的角度看它(希望你还和我在一起)最后我假设相应的内核线程正在由 CPU 调度程序处理,其中在上下文切换中会发生从用户级线程到相应的内核级线程当fopen系统调用被应答时。

我做了很多假设,如果有人能够消除疑虑或至少引导我朝着正确的方向前进,那将是非常棒的。

4

1 回答 1

9

注意:我主要使用 ARM 机器,所以其中一些可能是 ARM 特定的。另外,我会尽量简化它。随意纠正任何可能错误或过于简单化的内容。

假设线程进行系统调用。我对这之后的工作有点不清楚。中断将产生一个调用。我的一个问题是谁来接听这个电话?

通常,处理器将在内核模式下的某个预定位置开始执行。内核将保存当前进程状态并查看用户空间寄存器以确定请求了哪个系统调用并将其分派给正确的系统调用处理程序。

因此内核将查找中断向量表并获取需要执行的例程。我的下一个问题是执行中断时将使用哪个堆栈?是内核线程的堆栈还是用户级线程的堆栈?(我假设它将是内核线程的堆栈。)

我很确定它会切换到内核堆栈。如果他们使用用户空间堆栈,将会有一些非常严重的信息泄漏安全问题。

回到程序流程,假设操作是使用 fopen 打开文件。我的下一个问题是如何从 ISR 跳转到系统调用?或者我们的 ISR 是否映射到系统调用?

fopen()实际上是一个 libc 函数,而不是系统调用本身。不过,它可能(并且在大多数情况下会)open()在其实现中调用系统调用。

所以,这个过程(大致)是:

  1. 用户空间调用fopen()
  2. fopen执行系统调用open()
  3. 这会触发某种异常或中断。作为响应,处理器切换到特权模式并开始在内核中的某个预设位置执行。
  4. 内核确定它是什么类型的中断和异常并适当地处理它。在我们的例子中,它将是一个系统调用。
  5. 内核通过读取用户空间寄存器并提取任何参数并将其传递给适当的处理程序来确定正在请求哪个系统调用。
  6. 处理程序运行。
  7. 内核将任何返回码放入用户空间寄存器。
  8. 内核将执行转移回发生异常的地方。

同样在更广泛的情况下,当内核线程正在执行时,我假设 RAM 上的“OS 区域”将用于容纳正在执行系统调用的页面。

页面不执行任何操作 :) 通常,在 Linux 中,映射到 0xC0000000 以上的任何地址都属于内核。

再次从不同的角度看它(希望你还和我在一起)最后我假设相应的内核线程正在由 CPU 调度程序处理,其中在上下文切换中会发生从用户级线程到相应的内核级线程当 fopen 系统调用被应答时。

使用抢占式内核,线程实际上不会受到歧视。据我了解,新线程并不是为了服务系统调用而创建的——它只是在请求系统调用的同一个线程中运行,但内核模式除外。

这意味着在内核模式下为系统调用服务的线程可以像任何其他线程一样被调度。因此,这是您在为内核开发时听到“用户空间上下文”的地方。这意味着它在用户模式线程上以内核模式执行。

这有点难以解释,所以我希望我做对了。

于 2013-04-10T10:09:14.520 回答