POSIX 取消点应该如何表现?

发布于 2024-10-02 22:57:20 字数 772 浏览 3 评论 0原文

我一直在研究 glibc/nptl 取消点的实现,并将其与 POSIX 进行比较,除非我弄错了,否则它是完全错误的。使用的基本模型是:

int oldtype = LIBC_ASYNC_CANCEL(); /* switch to asynchronous cancellation mode */
int result = INLINE_SYSCALL(...);
LIBC_CANCEL_RESET(oldtype);

根据 POSIX:

在函数调用期间挂起时执行取消请求的副作用与单线程程序中函数调用被信号中断时可能出现的副作用相同并且给定的函数返回[EINTR]。任何此类副作用都会在调用任何取消清理处理程序之前发生。

我对这段文字的解读是,如果我调用 open,我可以期望它在无法打开文件之前或者被取消(以及我的整个线程),< em>或返回一个有效的文件描述符或-1和errno值,但永远不要创建一个新的文件描述符然后将其丢失。另一方面,取消点的 glibc/nptl 实现似乎允许竞争条件,其中取消请求发生在系统调用返回之后、LIBC_CANCEL_RESET 发生之前。

我是疯了,还是他们的实施真的这么糟糕?如果是这样,POSIX 是否允许这种破坏行为(这似乎使取消完全无法使用,除非您手动推迟),或者他们只是公然忽略 POSIX?

如果这种行为实际上被破坏了,那么在没有这种竞争条件的情况下实现它的正确方法是什么?

I've been looking at glibc/nptl's implementation of cancellation points, and comparing it to POSIX, and unless I'm mistaken it's completely wrong. The basic model used is:

int oldtype = LIBC_ASYNC_CANCEL(); /* switch to asynchronous cancellation mode */
int result = INLINE_SYSCALL(...);
LIBC_CANCEL_RESET(oldtype);

According to POSIX:

The side-effects of acting upon a cancellation request while suspended during a call of a function are the same as the side-effects that may be seen in a single-threaded program when a call to a function is interrupted by a signal and the given function returns [EINTR]. Any such side-effects occur before any cancellation cleanup handlers are called.

My reading of this passage is that if I call open, I can expect it either to get cancelled (along with my whole thread) before it fails to open a file, or to return a valid file descriptor or -1 and errno value, but never to create a new file descriptor then lose it into the void. On the other hand, the glibc/nptl implementation of cancellation points seems to allow for a race condition where the cancellation request occurs just after the syscall returns but before LIBC_CANCEL_RESET takes place.

Am I crazy, or is their implementation really this broken? And if so, does POSIX allow such broken behavior (which seems to render cancellation completely unusable unless you defer it manually), or are they just blatantly ignoring POSIX?

If this behavior is in fact broken, what's the correct way to implement it without such a race condition?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

瑾夏年华 2024-10-09 22:57:20

标准的下一段不是澄清了这一点吗:

但是,如果线程挂起于
取消点和事件
它正在等待发生在
取消请求被执行,它
未指定是否
取消请求已采取行动或
是否取消请求
保持挂起状态并且线程恢复
正常执行。

这意味着这种竞争条件是完全合法的行为。

Isn't this clarified in the next paragraph of the standard:

However, if the thread is suspended at
a cancellation point and the event for
which it is waiting occurs before the
cancellation request is acted upon, it
is unspecified whether the
cancellation request is acted upon or
whether the cancellation request
remains pending and the thread resumes
normal execution.

Which implies that this race condition is perfectly legal behaviour.

护你周全 2024-10-09 22:57:20

这是 确认为 glibc 中的错误并在 提交 6fe99352106cf8f244418f3708b3d5928e82e831

POSIX 文本明确表示在取消的情况下不可能已经发生副作用。 cmeerw 的回答中引用的文字,如果

它正在等待的事件发生在取消请求执行之前,未指定是否执行取消请求或取消请求是否保持挂起状态并且线程恢复正常执行。

如果正在等待的事件(例如设备变得可用、文件描述符变得可读等)已经发生,则允许实现对取消进行操作,但如果事件已经发生,则不允许执行此操作被消耗或以其他方式产生一些副作用(例如打开设备并分配文件描述符、消耗来自管道或套接字的数据等)。

This was acknowledged as a bug in glibc and fixed in commit 6fe99352106cf8f244418f3708b3d5928e82e831.

The POSIX text is unambiguous that side effects cannot already have happened in the case of cancellation. The text quoted in cmeerw's answer, that if the

event for which it is waiting occurs before the cancellation request is acted upon, it is unspecified whether the cancellation request is acted upon or whether the cancellation request remains pending and the thread resumes normal execution.

allows an implementation to act on cancellation if the event being waited for (e.g. device to become available, file descriptor to become readable, etc.) has already occurred, but does not allow this if the event has already been consumed or otherwise had some side effect (e.g. opening the device and allocating a file descriptor, consuming data from a pipe or socket, etc.).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文