gpt4 book ai didi

c - sigsuspend 与处理程序执行期间传递的其他信号

转载 作者:行者123 更新时间:2023-12-02 22:17:59 31 4
gpt4 key购买 nike

sigsuspend 更改信号掩码,暂停调用线程的执行,直到它接收到“其 Action 是执行信号捕获函数或终止进程的信号”,然后(如果进程没有终止并且信号处理程序返回)将信号掩码恢复到其原始状态。

POSIX.1-2008 的链接页面没有说明是否可以在一次调用 sigsuspend 中传递多个信号。 ,也没有说明信号掩码变化的原子性;即在我看来,这是符合 sigsuspend 的实现, 即使 sigsuspend 的整点是它没有此代码所具有的竞争条件:

int sigsuspend(const sigset_t *mask)
{
sigset_t oldmask;
if (sigprocmask(SIG_SETMASK, mask, &oldmask)) return -1;
pause();
if (sigprocmask(SIG_SETMASK, &oldmask, 0)) return -1;
return -1;
}

我真正担心的场景是一个使用 SIGUSR1 的程序。与自身通信(这是一个很长的故事),我需要一种方法来确保信号处理程序每​​次对 sigsuspend 的内部调用只执行一次,即使同一系统上的其他进程向它发送信号。

所以我的问题是:
  • 是否有要求(在 POSIX 或任何其他相关标准中)每次调用 sigsuspend 时最多提供一个信号(任何类型)?
  • sigsuspend 是否需要(同上)以原子方式更改信号掩码、暂停执行和恢复信号掩码?也就是说,在上面假设的用户空间实现中,没有任何信号将在三个系统调用“之间”传递的风险?

  • 由于这是相当抽象的,所以在我希望始终打印 1 并成功退出的测试程序下面,但我担心在某些情况下它可能会打印 2 或 0,挂起直到警报响起或崩溃。 (出于过分谨慎使用 C11 原子;从技术上讲,您不允许从信号处理程序读取 volatile sig_atomic_t,只能写入一个。)默认情况下使用 SIGUSR1,如果您通过 -r,则使用 SIGRTMIN在命令行上。
    #define _XOPEN_SOURCE 700
    #include <stdatomic.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <signal.h>
    #include <unistd.h>

    #ifndef ATOMIC_INT_LOCK_FREE
    #error "This program uses atomic_uint from a signal handler."
    #endif

    static atomic_uint handler_call_count;
    static pid_t self_pid;

    static void perror_exit(const char *msg)
    {
    perror(msg);
    exit(1);
    }

    static void handler(int signo)
    {
    union sigval dummy;
    dummy.sival_int = 0;

    if (handler_call_count++ == 0)
    if (sigqueue(self_pid, signo, dummy))
    perror_exit("sigqueue");
    }

    int main(int argc, char **argv)
    {
    sigset_t mask1, mask2;
    struct sigaction sa;
    int signo;
    union sigval dummy;

    if (argc > 1 && !strcmp(argv[1], "-r"))
    signo = SIGRTMIN;
    else
    signo = SIGUSR1;

    sigemptyset(&mask1);
    sigemptyset(&sa.sa_mask);

    sigaddset(&mask1, signo);
    sigaddset(&sa.sa_mask, signo);

    if (sigprocmask(SIG_BLOCK, &mask1, &mask2))
    perror_exit("sigprocmask");

    sigdelset(&mask2, SIGALRM);
    sigdelset(&mask2, signo);

    sa.sa_handler = handler;
    sa.sa_flags = SA_RESTART;
    if (sigaction(signo, &sa, 0))
    perror_exit("sigaction");

    self_pid = getpid();
    dummy.sival_int = 0;
    if (sigqueue(self_pid, signo, dummy))
    perror_exit("sigqueue");

    alarm(5);
    sigsuspend(&mask2);
    alarm(0);

    printf("%u\n", atomic_load(&handler_call_count));
    return 0;
    }

    最佳答案

    1) 是否要求最多处理一个信号?

    号码事实上,建议相反。 POSIX 2008 的第 4 卷:基本原理,§B.2.4.1 信号生成和传递状态:

    When there are multiple pending signals that are not blocked, implementations should arrange for the delivery of all signals at once, if possible. Some implementations stack calls to all pending signal-catching routines, making it appear that each signal-catcher was interrupted by the next signal. In this case, the implementation should ensure that this stacking of signals does not violate the semantics of the signal masks established by sigaction(). Other implementations process at most one signal when the operating system is entered, with remaining signals saved for later delivery. Although this practice is widespread, this behavior is neither standardized nor endorsed. In either case, implementations should attempt to deliver signals associated with the current state of the process (for example, SIGFPE) before other signals, if possible.



    而且,它 可以同时对具有相同信号编号的多个信号进行排队。 POSIX 2008 第 2 卷:系统接口(interface),§2.4.1 信号生成和传递状态

    If a subsequent occurrence of a pending signal is generated, it is implementation-defined as to whether the signal is delivered or accepted more than once in circumstances other than those in which queuing is required. The order in which multiple, simultaneously pending signals outside the range SIGRTMIN to SIGRTMAX are delivered to or accepted by a process is unspecified.



    这也适用于实时信号。 POSIX 2008 第 2 卷:系统接口(interface),§2.4.2 实时信号生成和传递状态

    [...] Multiple occurrences of signals so generated are queued in FIFO order. [...]

    If, when a pending signal is delivered, there are additional signals queued to that signal number, the signal shall remain pending. Otherwise, the pending indication shall be reset.



    2)对原子性有要求吗?

    合法有争议。 这可能是有意的,但实际上并没有规范地说明。赞成和反对都有很好的论据:

    原子性的情况:

    POSIX 2008 在第 2 卷中强烈暗示原子性:系统接口(interface),§3 pause() :

    APPLICATION USAGE

    Many common uses of pause() have timing windows. The scenario involves checking a condition related to a signal and, if the signal has not occurred, calling pause(). When the signal occurs between the check and the call to pause(), the process often blocks indefinitely. The sigprocmask() and sigsuspend() functions can be used to avoid this type of problem.



    下出现了类似的强烈暗示。基本原理 前往 sleep() .此外, 这个词可以在 POSIX 2008 第 1 卷:基本定义,§1.5 术语中定义为:

    For the purposes of POSIX.1-2008, the following terminology definitions apply:

    can

    Describes a permissible optional feature or behavior available to the user or application. The feature or behavior is mandatory for an implementation that conforms to POSIX.1-2008. An application can rely on the existence of the feature or behavior.



    POSIX 2008 的第 4 卷:基本原理,§A.1.5 术语指出:

    may

    The use of may has been limited as much as possible, due both to confusion stemming from its ordinary English meaning and to objections regarding the desirability of having as few options as possible and those as clearly specified as possible.

    The usage of can and may were selected to contrast optional application behavior (can) against optional implementation behavior (may).



    也就是说, pause()应用使用 标题表明应用程序没有义务调用 sigsuspend()为了避免时间问题,但如果它选择这样做,那么 sigsuspend() 的符合 POSIX.1-2008 的实现需要避免上述时间窗口问题(例如,在内核的帮助下是原子的)。

    如果 sigsuspend()不是原子的,那么
  • 应用程序可以通过使用 sigsuspend() 避免计时窗口问题的声明是错误的,因此自 1988 年第一个标准以来的所有 POSIX.1 标准版本在内部都是不一致的。
  • sigsuspend()将毫无用处,因为它在 pause() 之外毫无用处。 .然后有人会问为什么 POSIX.1 从第一个版本开始就包含这两者,以及使用 sigsuspend() 的错误建议。优先于 pause() .

  • 反对原子性的案例:

    POSIX 2008 第 2 卷:系统接口(interface),§1.2 条目格式说明:

    [...]

    APPLICATION USAGE

    This section is informative.

    This section gives warnings and advice to application developers about the entry. In the event of conflict between warnings and advice and a normative part of this volume of POSIX.1-2008, the normative material is to be taken as correct.

    RATIONALE

    This section is informative.

    This section contains historical information concerning the contents of this volume of POSIX.1-2008 and why features were included or discarded by the standard developers.

    [...]



    这意味着这些部分是信息性的,而不是规范性的,只有规范性部分才能直接对实现者提出要求。但是,它们可以帮助解释标准,并且“ sigprocmask()sigsuspend() 函数可用于避免此类问题”的声明与标准的任何规范部分都不冲突。

    中性案例

    POSIX 2008 的第 4 卷:基本原理,§A.1.5 术语指出:

    implementation-defined

    This definition is analogous to that of the ISO C standard and, together with ‘‘undefined’’ and ‘‘unspecified’’, provides a range of specification of freedom allowed to the interface implementor.

    [...]

    unspecified

    See implementation-defined.

    [...]

    In many places POSIX.1-2008 is silent about the behavior of some possible construct. For example, a variable may be defined for a specified range of values and behaviors are described for those values; nothing is said about what happens if the variable has any other value. That kind of silence can imply an error in the standard, but it may also imply that the standard was intentionally silent and that any behavior is permitted. There is a natural tendency to infer that if the standard is silent, a behavior is prohibited. That is not the intent. Silence is intended to be equivalent to the term ‘‘unspecified’’.



    ISO C 标准(目前为 C11)将“实现定义的行为”定义为实现可以选择但必须记录其选择的行为。

    没有任何关于 sigsuspend() 原子性的规范性声明可能是错误或等同于明确声明它是实现定义的行为。
  • pause() 中的应用说明和基本原理和 sleep()表明这是标准中的错误。
  • 但相反,一个隐含的规范性陈述 sigsuspend()的原子性是实现定义的优先于信息性声明相反。

  • 实现

    那么我们可以从野外实现中激发自己吗?也许。我知道没有不以原子方式实现它的实现:
  • Linux 内核实现 sigsuspend()原子地。
  • BSD 内核实现 sigsuspend()原子地。
  • 关于c - sigsuspend 与处理程序执行期间传递的其他信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40592066/

    31 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com