最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c - pause() might be blocking previous signals - Stack Overflow

programmeradmin1浏览0评论

I'm basically trying to implement a mini chat between two processes using only unix signals. For that purpose, I have some code where I call pause() to wait for some signals, that are handled with a handler function:

void    sigusers_handler(int signal)
{
    if (signal == SIGUSR1)
        printf("1 ");
    else if (signal == SIGUSR2)
        printf("0 ");
    else if (signal == SIGINT)
        exit(0);
    else
        printf("Unkonw signal\n");
    pause();
}

void    init_signal(void (*sighandler)(int), int size, ...)
{
    va_list sigs_list;
    int     idx;
    int     current_signal;

    idx = 0;
    va_start(sigs_list, size);
    while (idx < size)
    {
        current_signal = va_arg(sigs_list, int);
        signal(current_signal, sighandler);
        idx++;
    }
}


int main(void)
{
    pid_t   self_pid;

    self_pid = getpid();
    init_signal(sigusers_handler, 3, SIGUSR1, SIGUSR2, SIGINT);
    ft_printf("Server Pid is : %d\n", self_pid);
    while (1)
        pause();
    return (0);
}

When I run the program and send it signals via the kill command, like so:

kill -SIGUSR1 its_pid
kill -SIGUSR2 its_pid
kill -SIGUSR2 its_pid
kill -SIGUSR1 its_pid

... it doesn't produce any output. Why not?

I think the problem was that pause() was called within a signal handler so it'll pause within the action, and the same signal will just be ignored if called again.

I'm basically trying to implement a mini chat between two processes using only unix signals. For that purpose, I have some code where I call pause() to wait for some signals, that are handled with a handler function:

void    sigusers_handler(int signal)
{
    if (signal == SIGUSR1)
        printf("1 ");
    else if (signal == SIGUSR2)
        printf("0 ");
    else if (signal == SIGINT)
        exit(0);
    else
        printf("Unkonw signal\n");
    pause();
}

void    init_signal(void (*sighandler)(int), int size, ...)
{
    va_list sigs_list;
    int     idx;
    int     current_signal;

    idx = 0;
    va_start(sigs_list, size);
    while (idx < size)
    {
        current_signal = va_arg(sigs_list, int);
        signal(current_signal, sighandler);
        idx++;
    }
}


int main(void)
{
    pid_t   self_pid;

    self_pid = getpid();
    init_signal(sigusers_handler, 3, SIGUSR1, SIGUSR2, SIGINT);
    ft_printf("Server Pid is : %d\n", self_pid);
    while (1)
        pause();
    return (0);
}

When I run the program and send it signals via the kill command, like so:

kill -SIGUSR1 its_pid
kill -SIGUSR2 its_pid
kill -SIGUSR2 its_pid
kill -SIGUSR1 its_pid

... it doesn't produce any output. Why not?

I think the problem was that pause() was called within a signal handler so it'll pause within the action, and the same signal will just be ignored if called again.

Share Improve this question asked Feb 14 at 15:07 DiasDias 311 silver badge4 bronze badges 2
  • Please note that printf is not considered signal safe, and thus shouldn't really be used in signal handlers. – Some programmer dude Commented Feb 14 at 15:15
  • 1 Besides that, when stdout (where printf writes) is connected to an interactive terminal, it's line buffered. Which means the output is flushed (actually written) when you print a newline. – Some programmer dude Commented Feb 14 at 15:16
Add a comment  | 

2 Answers 2

Reset to default 5

I think the problem was that pause() was called within a signal handler so it'll pause within the action, and the same signal will just be ignored if called again.

Calling pause() inside the signal handler is one issue. You having registered the handler via the signal() function instead of the sigaction() function, it's unclear whether additional signals of the same type are blocked while your signal handler is executing, but either way you have trouble. If they are blocked then your program will receive up to one signal of each type for which the handler is registered. If they are not blocked then you effectively have an unbounded recursion. Signal handlers should do their work and return quickly. I see no good reason for yours to pause() when the main program is itself repeatedly pause()ing.

At least two other issues revolve around your use of printf in the signal handler. In the first place, printf is not async-signal-safe, so calling it from a signal handler produces undefined behavior. In practice, sometimes you can get away with that, and sometimes you can't, and you oughtn't to risk it. In the second place, printf() writes to the standard output, which typically is buffered, so you shouldn't expect to see any output anyway until the buffer is flushed. Since you're not writing any newlines, that won't happen until the buffer fills (and its size is unspecified). You can solve both problems by using write() instead of printf() to emit your output.

As a side issue, you should strive to avoid writing variadic functions, and you don't need one here. Instead, let init_signal() accept a pointer to the first element of an array of signal numbers, and let it access the signal numbers via the pointer, as an array. That will simplify the init_signal()'s implementation and make main() clearer.

Also, when you do write a variadic function, you must not fail to match each use of va_start() with a corresponding va_end().

Pause neither blocks signals, nor dispaches them. On side effect of signals is that they interrupt any blocking system call. And this is the use of pause() to wait for a signal to occur. But the blocking of signals is not handled by pause();

If you pause in a signal handler, it will not block signals at all. What can happen is that you get a second signal. You trigger the same signal handler if not blocked, and it will be blocked if you configured it to block signals, but the pause() will be released anyway, and you will have a second signal handler call in quick sequence, as soon as your signal handler returns from the pause.

In unix, a signal handler runs in the same context as the process, and runs in user mode, which is the reason to delay signal handlers to when they return from a system call. Being in a system call, makes the system to interrupt the system call... and when the system returns to user mode, the code corresponding to the second call is called.... making another pause() call....

The result will be that you will still continue processing the calls, but you will never return to non-handler code, because the new call makes the process to pause again.

In new systems (I'm not aware of linux, but FreeBSD does) the signal handlers run in user mode in a different context (like a process thread) which allows you to pause in a signal handler.... forever :) (forever not, but it depends who is the catcher of the signal).

发布评论

评论列表(0)

  1. 暂无评论