Linux 系统调用流程序列
Posted
技术标签:
【中文标题】Linux 系统调用流程序列【英文标题】:Linux System Call Flow Sequence 【发布时间】:2013-04-01 19:18:02 【问题描述】:我有一个关于 Linux 的深度工作的问题。
假设一个多线程进程正在 CPU 中执行。在这种情况下,我们将有一个正在 CPU 上执行的线程。在更广泛的情况下,我们会将属于进程的相应页面加载到 RAM 中以供执行。
假设线程进行系统调用。我对这之后的工作有点不清楚。中断将产生一个调用。我的一个问题是谁来接听这个电话?
假设系统有 m:n 个用户级线程到内核级线程的映射,我假设相应的内核级线程会响应这个调用。
因此内核将查找中断向量表并获取需要执行的例程。我的下一个问题是执行中断时将使用哪个堆栈?是内核线程的堆栈还是用户级线程的堆栈? (我假设它将是内核线程的堆栈。)
回到程序流程,假设操作是使用fopen
打开文件。我的下一个问题是如何从 ISR 跳转到系统调用?或者我们的 ISR 是否映射到系统调用?
在更广泛的情况下,当内核线程正在执行时,我假设 RAM 上的“OS 区域”将用于容纳正在执行系统调用的页面。
再次从不同的角度看它(希望你还和我在一起)最后我假设相应的内核线程正在由 CPU 调度程序处理,其中在上下文切换中会发生从用户级线程到相应的回答fopen
系统调用时的内核级线程。
我做了很多假设,如果有人能够消除疑虑或至少引导我朝着正确的方向前进,那将是非常棒的。
【问题讨论】:
您介意重新格式化文字墙,使其更易于阅读吗?谢谢。 另外,阅读几本关于 Linux 编程的书籍。您首先需要了解应用程序方面,例如advancedlinuxprogramming.com那你需要了解内核的观点,还有很多书籍也存在... 嗨,Basile,我已经阅读了多本关于 Linux 的书籍,它们几乎给了我相同的信息。但是,我无法将所有内容拼接在一起。整个过程如何实时进行。 【参考方案1】:注意:我主要使用 ARM 机器,所以其中一些可能是 ARM 特定的。另外,我会尽量简化它。随意纠正任何可能错误或过于简单化的地方。
假设线程进行系统调用。我对这之后的工作有点不清楚。中断将产生一个调用。我的一个问题是谁来接听这个电话?
通常,处理器将在内核模式下的某个预定位置开始执行。内核将保存当前进程状态并查看用户空间寄存器以确定请求了哪个系统调用并将其分派给正确的系统调用处理程序。
因此内核将查找中断向量表并获取需要执行的例程。我的下一个问题是执行中断时将使用哪个堆栈?是内核线程的堆栈还是用户级线程的堆栈? (我假设它将是内核线程的堆栈。)
我很确定它会切换到内核堆栈。如果他们使用用户空间堆栈,将会有一些非常严重的信息泄漏安全问题。
回到程序流程,假设操作是使用 fopen 打开文件。我的下一个问题是如何从 ISR 跳转到系统调用?或者我们的 ISR 是否映射到系统调用?
fopen()
实际上是一个 libc 函数,而不是系统调用本身。不过,它可能(并且在大多数情况下会)在其实现中调用 open()
系统调用。
所以,过程(大致)是:
-
用户空间调用
fopen()
fopen
对open()
执行系统调用
这会触发某种异常或中断。作为响应,处理器切换到特权模式并开始在内核中的某个预设位置执行。
内核确定它是什么类型的中断和异常并适当地处理它。在我们的例子中,它是一个系统调用。
内核通过读取用户空间寄存器并提取任何参数并将其传递给适当的处理程序来确定正在请求哪个系统调用。
处理程序运行。
内核将任何返回码放入用户空间寄存器。
内核将执行转移回发生异常的地方。
在更广泛的情况下,当内核线程正在执行时,我假设 RAM 上的“OS 区域”将用于容纳正在执行系统调用的页面。
页面不执行任何操作 :) 通常,在 Linux 中,任何映射到 0xC0000000 以上的地址都属于内核。
再次从不同的角度看它(希望你还和我在一起)最后我假设相应的内核线程正在由 CPU 调度程序处理,其中在上下文切换中会发生从用户级线程到相应的应答 fopen 系统调用时的内核级线程。
使用抢占式内核,线程实际上不会受到歧视。据我了解,新线程不是为了服务系统调用而创建的——它只是在请求系统调用的同一线程中运行,内核模式除外。
这意味着在内核模式下为系统调用服务的线程可以像任何其他线程一样被调度。因此,这是您在为内核开发时听到“用户空间上下文”的地方。这意味着它在用户模式线程上以内核模式执行。
这有点难以解释,所以我希望我是对的。
【讨论】:
我有一个小的后续问题。在上一段中,您提到线程将处于两种模式,即用户模式和内核模式。因此,根据我的理解,当进行系统调用时,线程会从用户模式进入内核模式。我的问题是这如何适应 Linux 支持的线程模型,例如 1;1、1:n 和 m:n 线程。因此,如果我们有 1:n 并且当两个线程同时进行系统调用时我们有 2 个线程,另一个将被阻塞,直到该线程的服务完成? 取决于什么样的系统调用。如果它们完全不相关,它们根本不会阻塞,它们只会并行运行。如果他们都试图访问内核中的相同资源,那将取决于该资源在内核中的锁定方式。这可能意味着一个线程被阻塞,直到另一个线程完成访问资源。以上是关于Linux 系统调用流程序列的主要内容,如果未能解决你的问题,请参考以下文章
Linux 内核 内存管理内存管理架构 ④ ( 内存分配系统调用过程 | 用户层 malloc free | 系统调用层 brk mmap | 内核层 kmalloc | 内存管理流程 )
Linux 内核 内存管理mmap 系统调用源码分析 ⑤ ( mmap_region 函数执行流程 | mmap_region 函数源码 )
Linux 内核 内存管理mmap 系统调用源码分析 ④ ( do_mmap 函数执行流程 | do_mmap 函数源码 )