gpt4 book ai didi

c - 在用户空间中实现可取消的系统调用

转载 作者:IT王子 更新时间:2023-10-29 00:14:46 28 4
gpt4 key购买 nike

我正在努力在 Linux 上实现 pthread 取消,而没有在我最近的其他一些问题中讨论过的任何“令人不快的行为”(有些人可能会说是错误)。到目前为止,Linux/glibc 的 pthread 取消方法一直将其视为不需要内核支持的东西,并且可以在库级别纯粹通过在进行系统调用之前启用异步取消并恢复先前的取消状态来处理系统调用返回后。这至少有两个问题,其中一个非常严重:

  • 取消可以在系统调用从内核空间返回之后,但在用户空间保存返回值之前执行。如果系统调用分配了资源,这将导致资源泄漏,并且无法使用取消处理程序修补它。
  • 如果在线程被可取消系统调用阻塞时处理信号,则整个信号处理程序将在启用异步取消的情况下运行。这可能非常危险,因为信号处理程序可能会调用异步信号安全但不是异步取消安全的函数。

  • 我解决这个问题的第一个想法是设置一个标志,表明线程处于取消点,而不是启用异步取消,当设置了这个标志时,让取消信号处理程序检查保存的指令指针,看看它是否指向系统调用指令(特定于架构)。如果是这样,这表明系统调用未完成,将在信号处理程序返回时重新启动,因此我们可以取消。如果没有,我假设系统调用已经返回,并推迟取消。但是,还有一个竞争条件——线程可能根本没有到达系统调用指令,在这种情况下,系统调用可能会阻塞并且永远不会响应取消。另一个小问题是,如果在输入信号处理程序时设置了取消点标志,则从信号处理程序执行的不可取消的系统调用会错误地变为可取消。

    我正在寻找一种新方法,并寻求有关它的反馈。必须满足的条件:
  • 在系统调用完成之前收到的任何取消请求必须在系统调用阻塞之前的任何重要时间间隔内执行,但不是在由于信号处理程序中断而等待重新启动时执行。
  • 系统调用完成后收到的任何取消请求都必须推迟到下一个取消点。

  • 我的想法需要为可取消的系统调用包装器专门组装。基本思想是:
  • 将即将到来的 syscall 指令的地址压入堆栈。
  • 将堆栈指针存储在线程本地存储中。
  • 从线程本地存储中测试取消标志;如果设置,则跳转到取消例程。
  • 进行系统调用。
  • 清除保存在线程本地存储中的指针。

  • 取消操作将涉及:
  • 在目标线程的线程本地存储中设置取消标志。
  • 测试目标线程的线程本地存储中的指针;如果它不为空,则向目标线程发送取消信号。

  • 然后取消信号处理程序将:
  • 检查保存的堆栈指针(在信号上下文中)是否等于线程本地存储中保存的指针。如果不是,则取消点被信号处理程序中断,现在无事可做。
  • 检查程序计数器寄存器(保存在信号上下文中)是否小于或等于保存在保存的堆栈指针处的地址。如果是这样,这意味着系统调用尚未完成,我们执行取消。

  • 到目前为止我看到的唯一问题是在信号处理程序的第 1 步:如果它决定不采取行动,那么在信号处理程序返回后,线程可能会在系统调用上阻塞,忽略挂起的取消请求。为此,我看到了两个潜在的解决方案:
  • 在这种情况下,安装一个计时器来向特定线程传递信号,基本上每毫秒左右重试一次,直到我们走运。
  • 再次引发取消信号,但从取消信号处理程序返回而不取消屏蔽取消信号。当中断的信号处理程序返回时,它会自动取消屏蔽,然后我们可以再试一次。不过,这可能会干扰信号处理程序中取消点的行为。

  • 关于哪种方法最好的任何想法,或者我是否遗漏了其他更基本的缺陷?

    最佳答案

    解决方案 2 感觉不像是一个黑客。我认为这不会导致您建议的问题,因为在 syscall 处理程序中调用的可取消系统调用将检查 TLS 中的取消标志,如果取消信号处理程序已经运行并且无论如何都使用信号掩码,则必须已经设置了该标志。

    (如果每个阻塞系统调用都采用 sigmask 参数 a la pselect() ,似乎对实现者来说会容易得多)。

    关于c - 在用户空间中实现可取消的系统调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5684265/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com