【问题标题】:Does all system calls execute in kernel mode?所有系统调用都在内核模式下执行吗?
【发布时间】:2021-07-31 06:08:13
【问题描述】:

标题说明了一切:)。

但是,让我扩展一个特定的案例。

所以,到目前为止,我已经研究了所有需要硬件交互的系统调用(如 read()、write() 等),因此在执行这些系统调用之前切换到内核模式是有意义的(trap 指令)。

据我了解,信号纯粹是软件构造,这意味着它们不是由硬件直接生成的(与中断不同)。我理解它们是进程(内核-内核、内核-用户或用户-用户进程)之间的消息传递机制。

Kill 是一个系统调用,用于向进程发送信号。它不直接与硬件交互。那么为什么我们需要昂贵地切换到内核模式来执行该系统调用呢?我没有发现任何“特殊”系统调用的证据,这些系统调用在开始执行之前不会陷入内核模式。因此,问题。

【问题讨论】:

    标签: linux linux-kernel operating-system signals system-calls


    【解决方案1】:

    是的,也不是。

    系统调用的原始定义是/曾经是由某种陷阱调用的系统支持 (OS) 函数,而不是“正常”函数调用。所以根据这个定义,每个系统调用都需要切换到内核模式,就好像它不是系统调用(只是一个普通的系统库调用)一样。

    随着时间的推移,系统调用和库调用之间的区别已经变得模糊,因为传统上作为系统调用实现的事物(例如 getpid 或 gettimeofday)是通过其他方式实现的——通常是通过在内核中获取一些固定数据将为每个进程设置(并且可能偶尔修改)。在 Linux 上,正是出于这个原因,为每个用户进程创建了“vdso”(虚拟动态共享对象)的概念,因此一些“系统调用”实际上是作为对这个特殊内存空间的正常调用来实现的。

    即便如此,哪些函数是系统调用,哪些不是系统调用的精确定义仍然存在,因为为了向后兼容,所有系统调用继续通过陷阱/中断/系统调用接口可用;只是 vdso 中可用的那些通常永远不会通过陷阱调用。这允许在 vdso 存在之前编译的非常旧的 Linux 二进制文件继续工作。

    【讨论】:

    • 内核模式存在于硬件中以防止用户使用特权指令。例如进程是操作系统结构。硬件不知道过程。硬件无法防止用户使用特权指令。因为就软件结构而言,没有。 os 在内存中维护进程表,进程管理只是更新内存中的表(在最粗略的意义上)。任何人都可以与记忆互动。仅通过虚拟地址空间提供保护,因为一个进程不知道另一个进程的地址空间组织。我错过了什么吗?
    • 进程在非特权模式下运行,因此它们被“锁定”到它们的虚拟地址空间——它们只能与映射的内存进行交互,而不能更改这些映射。所以他们永远无法访问操作系统内存和进程管理表,并且需要进行系统调用以以受控方式更改任何映射(内核会验证没有“可疑”发生)。
    • 现在更有意义了。谢谢!
    【解决方案2】:

    信号不是沟通渠道,它更像是头上的一颗炸弹,能引起你的注意,但本身不携带任何信息。

    SIGKILL、SIGSTOP 等的语义是对进程调度器的请求,而不是目标线程本身,因此需要进入内核空间。

    信号由进程调度程序在线程被调度之前传递。这就是为什么处于不间断睡眠(D 状态)的进程如果从不醒来就无法移除的原因;他们永远不会被安排,因此无法传递任何信号。

    【讨论】:

    • 信号确实携带信息:参见man 2 sigaction中的siginfo_t
    • 是的,我知道这只是头脑中的一个“笨蛋”。但我无法理解切换到内核模式有什么帮助?如果实际上某些系统调用没有切换到内核模式,那么如何保护它们的内核数据结构不受用户影响?因为,纯软件构造(如 kill()、fork() 等)不使用可以预先设置的专用硬件指令。它们通常使用用户级指令,例如从内存加载和写入内存。
    • @RahulPatel 您的用户进程无法访问其他进程的内存来传递信号。
    • J Sible 从 sigaction 中提到了 siginfo_t。请注意,这主要是上下文信息,因此接收进程可以决定是否足够信任信号通知以对其采取行动。
    猜你喜欢
    • 1970-01-01
    • 2018-11-01
    • 1970-01-01
    • 2018-06-05
    • 1970-01-01
    • 2014-01-25
    • 2016-08-26
    • 2021-03-03
    • 1970-01-01
    相关资源
    最近更新 更多