实现在用户空间系统调用撤销 [英] Implementing cancellable syscalls in userspace

查看:138
本文介绍了实现在用户空间系统调用撤销的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我工作的实施在Linux上的pthread取消,没有任何的不愉快的行为的(有些人可能会说,错误)在我的一些其他问题最​​近讨论。在Linux / glibc的方法来取消的Pthread至今一直把它当作东西,并不需要内核支持,并且可以在图书馆级纯粹通过启用异步取消之前作出系统调用,并恢复$ P $处理系统调用返回后pvious取消状态。这至少有两个问题,其中一个极其严重的:

I'm working on implementing pthread cancellation on Linux without any of the "unpleasant behavior" (some might say bugs) discussed in some of my other recent questions. The Linux/glibc approach to pthread cancellation so far has been to treat it as something that doesn't need kernel support, and that can be handled at the library level purely by enabling asynchronous cancellation before making a syscall, and restoring the previous cancellation state after the syscall returns. This has at least 2 problems, one of them extremely serious:


  1. 系统调用从内核空间返回之后取消出手时就出手,但用户空间之前保存返回值。这将导致资源泄漏,如果系统调用分配的资源,而且也没有办法修补过它取消处理。

  2. 如果当线程被阻塞在系统调用撤销的信号处理,整个信号处理程序启用了异步取消运行。这可能是极其危险的,因为信号处理函数可以调用它们是异步信号安全的功能,但不是异步取消安全的。

我对解决这个问题的第一个想法是要设置一个标志,该线程在取消点,而不是启用异步取消,而当设置了这个标志,有消除信号处理程序检查保存的指令指针来看看它指向一个系统调用指令(弓专用)。如果是这样,这表明系统调用没有完成,将重新启动时的信号处理的回报,所以我们可以取消。如果没有,我承担了系统调用已经返回,延迟取消。然而,也有竞争状态 - 这可能是因为该线程还未达到系统调用指令在所有的,在这种情况下,该系统调用可以拦截与从未注销响应。另一个小问题是,从信号处理程序进行不可撤销的系统调用错误地成了撤销,如果输入信号处理程序时取消点已经设置。

My first idea for fixing the problem was to set a flag that the thread is at a cancellation point, rather than enabling async cancellation, and when this flag is set, have the cancellation signal handler check the saved instruction pointer to see if it points to a syscall instruction (arch-specific). If so, this indicates the syscall was not completed and would be restarted when the signal handler returns, so we can cancel. If not, I assumed the syscall had already returned, and deferred cancellation. However, there is also a race condition - it's possible that the thread had not yet reached the syscall instruction at all, in which case, the syscall could block and never respond to the cancellation. Another small problem is that non-cancellable syscalls performed from a signal handler wrongly became cancellable, if the cancellation point flag was set when the signal handler was entered.

我在寻找一种新的方法,并寻找它的反馈。必须满足以下条件:

I'm looking at a new approach, and looking for feedback on it. The conditions that must be met:


  • 任何要求取消之前收到的系统调用完成后,必须在任何时间间隔显著系统调用块之前采取行动,而不是当它挂起的重新启动,由于通过信号处理程序中断。

  • 收到的撤销请求后,系统调用完成后应推迟至下一个取消点。

这个想法我心目中需要的系统调用撤销的专业包装组装。其基本思路是:

The idea I have in mind requires specialized assembly for the cancellable syscall wrapper. The basic idea would be:


  1. 推即将到来的系统调用指令的地址压入堆栈。

  2. 存放在线程本地存储堆栈指针。

  3. 测试从线程本地存储取消标志;如果设置跳转到取消例程。

  4. 请系统调用。

  5. 清除保存在线程本地存储的指针。

取消操作,然后将包括:

The cancel operation would then involve:


  1. 设置目标线程的线程本地存储取消标志。

  2. 测试目标线程的线程本地存储的指针;如果它不为空,发送取消信号到目标线程。

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

The cancellation signal handler would then:


  1. 检查保存栈指针(在信号上下文)等于在线程局部存储器中的保存的指针。如果不是,那么取消点是由信号处理程序中断,并没有什么,现在做的事。

  2. 检查程序计数器寄存器(保存在信号上下文)小于或等于保存在保存栈指针的地址。如果是这样,这意味着系统调用还没有完成,我们执行取消。

我看到迄今唯一的问题是在信号处理程序的第1步:如果它决定不采取行动,那么信号处理函数返回后,线程可以留待阻塞系统调用,忽略挂起的取消请求。对于这一点,我看到了两个可能的解决方案:

The only problem I see so far is in step 1 of the signal handler: if it decides not to act, then after the signal handler returns, the thread could be left blocking on the syscall, ignoring the pending cancellation request. For this, I see two potential solutions:


  1. 在这种情况下,安装一个定时器来提供信号给特定线程,基本上是重试每毫秒左右,直到我们得到幸运。

  2. 再次提高抵消信号,但是从消除信号处理程序,而不揭露消除信号返回。它会自动获得东窗事发时被中断的信号处理程序返回,然后我们可以再次尝试。这可能与信号处理程序中取消点的行为干预,虽然。

任何思考哪种方法是最好的,或者有其他更根本性的缺陷我失踪?

Any thoughts on which approach is best, or if there are other more fundamental flaws I'm missing?

推荐答案

解决方案2感觉就像少了黑客攻击。我不认为这会造成贵方提出的问题,因为系统调用撤销所谓的系统调用处理程序内将检查TLS取消标志,它必须如果取消信号处理程序运行反正与信号屏蔽monkeyed已经设置。

Solution 2 feels like less of a hack. I don't think it would cause the problem you suggest, because cancellable syscalls called within the syscall handler will check the cancellation flag in TLS, which must have already been set if the cancellation signal handler has run and monkeyed with the signal mask anyway.

(好像如果每一个拦截系统调用了,这将是实施者更容易在 sigmask 参数一拉 PSELECT())。

(It seems like it would be much easier for implementers if every blocking syscall took a sigmask parameter a la pselect()).

这篇关于实现在用户空间系统调用撤销的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆