[英]Cancellation points in signal handlers?
What happens if a program calls a function which is a cancellation point from a signal handler? 如果程序调用函数作为信号处理程序的取消点会发生什么? There are a number of functions which POSIX specifies as both async-signal-safe and cancellation points.
POSIX指定了许多函数作为异步信号安全和取消点。 If a signal handler calls such a function and cancellation is acted upon, the result is quite similar to what would happen if the thread had enabled asynchronous cancellation - actually much worse, because all the cancellation cleanup handlers, which are probably not async-signal-safe, would be called from a signal-handler context.
如果一个信号处理程序调用了这样一个函数并且取消了,那么结果非常类似于线程启用异步取消时会发生什么 - 实际上更糟糕的是,因为所有的取消清理处理程序,可能都不是异步信号 - 安全,将从信号处理程序上下文调用。
What does POSIX actually specify in this case, and what do implementations actually do? 在这种情况下,POSIX实际指定了什么,以及实现实际上做了什么? I can't find any language in POSIX that would forbid cancellation points in signal handlers from being acted upon, nor any such protection in the glibc/nptl source.
我在POSIX中找不到任何禁止信号处理程序中的取消点被采取行动的语言,也没有在glibc / nptl源中找到任何此类保护。
I'm not aware that POSIX even dares to mention this topic, but I haven't done an exhaustive search. 我不知道POSIX甚至敢提这个话题,但我没有做过详尽的搜索。
Some brief experimentation with a gcc/nptl system reveals that, as I suspected and I think you did too, there is no such protection in NPTL - the cancellation handlers do indeed get called, from within the signal handler context. 使用gcc / nptl系统的一些简短实验表明,正如我所怀疑的那样,我认为你也是如此,NPTL中没有这样的保护 - 取消处理程序确实从信号处理程序上下文中被调用。
The program below (apologies for the hackiness etc) displays the following output: 下面的程序(为hackiness等道歉)显示以下输出:
Signal handler called
Sent cancellation
Cleanup called
In sighandler
... indicating that: ......表明:
pthread_cancel()
pthread_cancel()
Here's the program: 这是程序:
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
pthread_t mainthread;
int in_sighandler = 0;
void
cleanup (void *arg)
{
write(1, "Cleanup called\n", strlen("Cleanup called\n"));
if (in_sighandler) {
write(1, "In sighandler\n", strlen("In sighandler\n"));
} else {
write(1, "Not in sighandler\n", strlen("In sighandler\n"));
}
}
void
sighandler (int sig, siginfo_t *siginfo, void *arg)
{
in_sighandler = 1;
write(1,"Signal handler called\n", strlen("Signal handler called\n")); // write() is a CP
usleep(3000000); // usleep() is a CP; not strictly async-signal-safe but happens to be so in Linux
write(1, "Signal handler exit\n", strlen("Signal handler exit\n"));
in_sighandler = 0;
}
void *
thread (void *arg)
{
sleep(1);
pthread_kill(mainthread, SIGUSR1);
usleep(500000);
pthread_cancel(mainthread);
printf("Sent cancellation\n");
return (NULL);
}
int
main (int argc, char **argv)
{
int rc;
struct sigaction sa;
pthread_t threadid;
mainthread = pthread_self();
// Set up a signal handler to test its cancellation properties
sa.sa_sigaction = &sighandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
rc = sigaction(SIGUSR1, &sa, NULL);
assert(rc == 0);
// Set up a thread to send us signals and cancel us
rc = pthread_create(&threadid, NULL, &thread, NULL);
assert(rc == 0);
// Set up cleanup handlers and loop forever
pthread_cleanup_push(&cleanup, NULL);
while (1) {
sleep(60);
}
pthread_cleanup_pop(0);
return (0);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.