【问题标题】:Implementing cancellable syscalls in userspace在用户空间中实现可取消的系统调用
【发布时间】:2011-08-06 18:09:19
【问题描述】:

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

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

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

我正在寻找一种新方法,并寻求有关它的反馈。必须满足的条件:

  • 在系统调用完成之前收到的任何取消请求都必须在系统调用阻塞任何重要的时间间隔之前执行,而不是在它由于信号处理程序中断而等待重新启动时执行。
  • 系统调用完成后收到的任何取消请求都必须推迟到下一个取消点。

我的想法需要对可取消的系统调用包装器进行专门的组装。基本思想是:

  1. 将即将到来的系统调用指令的地址压入堆栈。
  2. 将堆栈指针存储在线程本地存储中。
  3. 从线程本地存储中测试取消标志;如果已设置,则跳转以取消例程。
  4. 进行系统调用。
  5. 清除保存在线程本地存储中的指针。

取消操作将涉及:

  1. 在目标线程的线程本地存储中设置取消标志。
  2. 测试目标线程的线程本地存储中的指针;如果不为空,则向目标线程发送取消信号。

然后取消信号处理程序会:

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

到目前为止,我看到的唯一问题是信号处理程序的第 1 步:如果它决定不采取行动,那么在信号处理程序返回后,线程可能会在系统调用上阻塞,忽略挂起的取消请求。为此,我看到了两种可能的解决方案:

  1. 在这种情况下,安装一个计时器以将信号传递到特定线程,基本上每毫秒重试一次,直到我们走运为止。
  2. 再次引发取消信号,但从取消信号处理程序返回而不取消屏蔽信号。当中断的信号处理程序返回时,它会自动取消屏蔽,然后我们可以重试。不过,这可能会干扰信号处理程序中取消点的行为。

对哪种方法最好有任何想法,或者我是否还遗漏了其他更根本的缺陷?

【问题讨论】:

    标签: c linux pthreads posix cancellation


    【解决方案1】:

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

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

    【讨论】:

    • 带括号的评论正是理想的解决方案。整个问题源于缺乏任何原子解除阻塞取消和进行系统调用的机制,并且需要在用户空间(看起来它们属于内核空间)中进行严重的黑客攻击才能解决它。
    • 你说得对,我的担心是错误的。当取消信号被“错误地”阻塞时,取消标志已经被设置并且信号处理程序执行的任何取消点都会立即行动,不需要信号来传递它。除非发现任何不可预见的问题,否则我倾向于将此答案标记为已接受。
    • @R.:我能想到的唯一另一个问题是取消操作和系统调用包装器之间需要一个内存屏障。
    • 再次感谢!实施似乎按预期工作。
    猜你喜欢
    • 2017-12-30
    • 1970-01-01
    • 1970-01-01
    • 2012-09-28
    • 2017-02-14
    • 1970-01-01
    • 2016-01-18
    • 2012-08-22
    • 2016-05-25
    相关资源
    最近更新 更多