POSIX取消点应该如何表现?

R..*_*R.. 10 c linux posix glibc pthreads

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

int oldtype = LIBC_ASYNC_CANCEL(); /* switch to asynchronous cancellation mode */
int result = INLINE_SYSCALL(...);
LIBC_CANCEL_RESET(oldtype);
Run Code Online (Sandbox Code Playgroud)

根据POSIX:

在函数调用期间暂停时对取消请求起作用的副作用与单个线程程序中可能在信号中断对函数的调用时看到的副作用相同函数返回[EINTR].任何此类副作用都会在调用任何取消清除处理程序之前发生.

我对这段经文的解读是,如果我打电话open,我可以预期它要么在它无法打开文件之前被取消(连同我的整个线程),要么返回有效的文件描述符或-1和errno值,但从不创建一个新的文件描述符,然后将其丢失到void中.另一方面,取消点的glibc/nptl实现似乎允许竞争条件,其中取消请求恰好在系统调用返回之后但在LIBC_CANCEL_RESET发生之前发生.

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

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

R..*_*R.. 0

这被认为是 glibc 中的一个错误,并在提交 6fe99352106cf8f244418f3708b3d5928e82e831中修复。

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

如果它正在等待的事件发生在对取消请求执行之前,则不确定是否对取消请求执行操作或取消请求是否保持挂起状态并且线程恢复正常执行。

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