Bug 58711 - real-time signals DO NOT delivered with the lowest-numbered first order.
Summary: real-time signals DO NOT delivered with the lowest-numbered first order.
Status: CLOSED INVALID
Alias: None
Product: Timers
Classification: Unclassified
Component: Other (show other bugs)
Hardware: All Linux
: P1 normal
Assignee: john stultz
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-05-23 16:41 UTC by Chopin
Modified: 2014-10-03 22:34 UTC (History)
3 users (show)

See Also:
Kernel Version: 3.2
Subsystem:
Regression: No
Bisected commit-id:


Attachments
test code, compile it using -std=c99 option (1.96 KB, application/octet-stream)
2013-05-23 16:41 UTC, Chopin
Details

Description Chopin 2013-05-23 16:41:29 UTC
Created attachment 102331 [details]
test code, compile it using -std=c99 option

Assume parent send 3 signals from SIGRTMAX (64) to SIGRTMAX - 2 (62), each signal sends 3 times, the child would recv the signal as order SIGRTMAX - 2 to SIGRTMAX, since the lowest-numbered should delivered first, and each same number signal deliver as FIFO order, but the result is:

-----parent send-----
sent 64, val = 1
sent 64, val = 2
sent 64, val = 3
sent 63, val = 1
sent 63, val = 2
sent 63, val = 3
sent 62, val = 1
sent 62, val = 2
sent 62, val = 3
-----child recv-----
recv 64, val = 1
recv 64, val = 2
recv 64, val = 3
recv 63, val = 1
recv 63, val = 2
recv 63, val = 3
recv 62, val = 1
recv 62, val = 2
recv 62, val = 3

we see that the same number signal deliver in right sequence (FIFO), but
different signal DO NOT delivered in lowest number first, in this case, it should be the signal 62 first, and 64 last.
Comment 1 Oleg Nesterov 2013-05-29 12:03:37 UTC
(In reply to comment #0)
>
> Assume parent send 3 signals from SIGRTMAX (64) to SIGRTMAX - 2 (62), each
> signal sends 3 times, the child would recv the signal as order SIGRTMAX - 2
> to
> SIGRTMAX, since the lowest-numbered should delivered first,
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Well, this is not true and this was never guaranteed.
For example, say, SIGSEGV will be delivered before SIGHUP.

(And in fact you meant "dequeued", not delivered ;)

But in this particular case this is true. The child dequeues
62 first, then 63, etc.

But note that if the task dequeues SIG_A before SIG_B, then
the handler for SIG_B will run first! This is correct. Because
the task dequeues both signals and setups the frames before
it returns to user-space, so the last handler runs first.

> recv 64, val = 1
> recv 64, val = 2
> recv 64, val = 3
> recv 63, val = 1
> recv 63, val = 2
> recv 63, val = 3

See above. everything is correct.

> we see that the same number signal deliver in right sequence (FIFO),

Given the above this probably needs another explanation. This is
because the dequeued signal becomes blocked until the signal handler
returns. If you change your test-case to add SA_NODEFER to sa_flags
the child should print

    recv 64 val = 3
         64       2
         64       1
         63       2
    ...

Not a bug.
Comment 2 Oleg Nesterov 2013-05-29 12:17:01 UTC
(In reply to comment #1)
>
> Not a bug.

Just in case. if you want FIFO you can initialize sa_mask
to exclude the signals you can "race" with.

#include <unistd.h>
#include <signal.h>
#include <stdio.h>

#define SIG_A   62
#define SIG_Z   64

void sig_func(int signum, siginfo_t *info, void *ucp)
{
        printf("recv %d, val = %d\n", signum, info->si_int);
}

int main(void)
{
        /* Block the signal. */
        sigset_t set;
        struct sigaction sa;
        union sigval val;
        int i, j;

        sigfillset(&set);
        sigprocmask(SIG_BLOCK, &set, NULL);

        sigemptyset(&sa.sa_mask);
        sa.sa_flags = SA_SIGINFO | SA_RESTART;
        sa.sa_sigaction = sig_func;
        sigfillset(&sa.sa_mask);        /* <--------------------------------- */
        for (i = SIG_A; i <= SIG_Z; i++)
                sigaction(i, &sa, NULL);

        printf("\nINIT DONE\n");

        for (i = SIG_A; i <= SIG_Z; i++) {
                for (j = 1; j <= 3; j++) {
                        val.sival_int = j;
                        sigqueue(getpid(), i, val);
                        printf("sent %d, val = %d\n", i, j);
                }
        }

        printf("\nSIGNALS SENT\n");
        sigprocmask(SIG_UNBLOCK, &set, NULL);

        return 0;
}

This code simply does sigfillset(sa_mask), but you only need
to block 62-64.
Comment 3 john stultz 2013-05-29 16:27:19 UTC
Closing as invalid per Oleg's feedback.
Comment 4 Chopin 2013-05-30 11:02:41 UTC
(In reply to comment #1)

> Well, this is not true and this was never guaranteed.
> For example, say, SIGSEGV will be delivered before SIGHUP.

Yes, for normal signal(SIGSEGV SIGHUP etc), it is not true.
but for real-time signal, the signal(7) says:
Real-time signals are delivered in a guaranteed  order.   Multiple
           real-time signals of the same type are delivered in the order they
           were sent.  If different real-time signals are sent to a  process,
           they  are  delivered  starting  with  the  lowest-numbered signal.


> (And in fact you meant "dequeued", not delivered ;)
> 
> But in this particular case this is true. The child dequeues
> 62 first, then 63, etc.
> 
> But note that if the task dequeues SIG_A before SIG_B, then
> the handler for SIG_B will run first! This is correct. Because
> the task dequeues both signals and setups the frames before
> it returns to user-space, so the last handler runs first.
> 
> > recv 64, val = 1
> > recv 64, val = 2
> > recv 64, val = 3
> > recv 63, val = 1
> > recv 63, val = 2
> > recv 63, val = 3
> 
> See above. everything is correct.
> 
> > we see that the same number signal deliver in right sequence (FIFO),
> 
> Given the above this probably needs another explanation. This is
> because the dequeued signal becomes blocked until the signal handler
> returns. If you change your test-case to add SA_NODEFER to sa_flags
> the child should print
> 
>     recv 64 val = 3
>          64       2
>          64       1
>          63       2
>     ...
> 
> Not a bug.
Comment 5 Chopin 2013-05-30 11:11:06 UTC
(In reply to comment #1)

> But in this particular case this is true. The child dequeues
> 62 first, then 63, etc.
> 
> But note that if the task dequeues SIG_A before SIG_B, then
> the handler for SIG_B will run first! This is correct. Because
> the task dequeues both signals and setups the frames before
> it returns to user-space, so the last handler runs first.
> 
> > recv 64, val = 1
> > recv 64, val = 2
> > recv 64, val = 3
> > recv 63, val = 1
> > recv 63, val = 2
> > recv 63, val = 3
> 
> See above. everything is correct.

Yes, this I got it. 
but I do not understand why man page say "If different real-time signals are sent to a  process, they  are  _delivered_  starting  with  the  lowest-numbered signal."
Comment 6 Oleg Nesterov 2013-05-31 14:43:32 UTC
(In reply to comment #5)
>
> but I do not understand why man page say "If different real-time signals are
> sent to a  process, they  are  _delivered_  starting  with  the 
> lowest-numbered signal."

I have no idea.

Except, as I already said, they are actually delivered starting with
the lowest-numbered signal, just this doesn't mean the handers will
run in the same order. Imho the man page should be fixed.

Look. Whatever the kernel does, you can't expect FIFO (in a sense you
described). Suppose that you send SIG_63 then SIG_64 to the task T.
What if the signal handler for SIG_63 has already started by the time
you send SIG_64? Depending on the timing, you can observe that the
handler for SIG_64 runs before or after.

Note You need to log in before you can comment on or make changes to this bug.