[PATCH] signals: real-time signals delivery order

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Anton Salikhmetov <[email protected]>

According to the POSIX standard, multiple real-time signals
pending to a process should be delivered in a strict order.
Specifically, the lowest-numbered signal should be delivered
first and multiple occurrences of signals with the same number
should be delivered in FIFO order.

Current Linux kernel delivers the highest-numbered signals
pending to a process first, not the lowest-numbered ones. This
contradicts to the requirement explained above. The problem can
be demonstrated by the following test program:

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

#define SIG_RAND (SIGRTMIN + rand() % (SIGRTMAX - SIGRTMIN + 1))
#define NUMSIG 7

struct {
	int sig, num;
} seq[NUMSIG];

void sh(int sig, siginfo_t *info, void *unused)
{
	static int cnt;
	seq[cnt].num = info->si_value.sival_int;
	seq[cnt++].sig = sig;
}

int main(int argc, char *argv[])
{
	int i;
	pid_t p = getpid();
	struct sigaction sa;
	sigset_t ss, ssold;
	union sigval sv;

	sigemptyset(&ss);
	for (i = SIGRTMIN; i <= SIGRTMAX; i++) {
		sa.sa_sigaction = sh;
		sa.sa_flags = SA_SIGINFO;
		sigemptyset(&sa.sa_mask);
		sigaction(i, &sa, NULL);
		sigaddset(&ss, i);
	}

	sigprocmask(SIG_BLOCK, &ss, &ssold);
	switch (fork()) {
		case -1:
			perror("fork()");
			return 1;
		case 0:
			srand(time(NULL));
			for (i = 0; i < NUMSIG; i++) {
				sv.sival_int = i;
				sigqueue(p, SIG_RAND, sv);
			}
			return 0;
		default:
			wait(NULL);
	}
	sigprocmask(SIG_SETMASK, &ssold, NULL);

	for (i = 0; i < NUMSIG; i++)
		printf("SIGRTMIN + %2d, sent with number %d\n",
			seq[i].sig - SIGRTMIN, seq[i].num);
	return 0;
}

Example of the program output for the original kernel:

SIGRTMIN + 23, sent with number 0
SIGRTMIN + 21, sent with number 1
SIGRTMIN + 21, sent with number 6
SIGRTMIN + 16, sent with number 2
SIGRTMIN + 15, sent with number 3
SIGRTMIN + 14, sent with number 4
SIGRTMIN +  5, sent with number 5

Example of the program output for the patched kernel:

SIGRTMIN + 2, sent with number 1
SIGRTMIN + 3, sent with number 0
SIGRTMIN + 17, sent with number 3
SIGRTMIN + 23, sent with number 5
SIGRTMIN + 25, sent with number 2
SIGRTMIN + 29, sent with number 6
SIGRTMIN + 30, sent with number 4

Patch for the Linux 2.6.22.1 kernel:

Signed-off-by: Anton Salikhmetov <[email protected]>
---
--- linux-2.6.22.1.orig/kernel/signal.c	2007-07-10 22:56:30.000000000
+0400
+++ linux-2.6.22.1/kernel/signal.c	2007-07-11 04:42:17.000000000 +0400
@@ -134,34 +134,11 @@
 
 int next_signal(struct sigpending *pending, sigset_t *mask)
 {
-	unsigned long i, *s, *m, x;
-	int sig = 0;
-	
-	s = pending->signal.sig;
-	m = mask->sig;
-	switch (_NSIG_WORDS) {
-	default:
-		for (i = 0; i < _NSIG_WORDS; ++i, ++s, ++m)
-			if ((x = *s &~ *m) != 0) {
-				sig = ffz(~x) + i*_NSIG_BPW + 1;
-				break;
-			}
-		break;
-
-	case 2: if ((x = s[0] &~ m[0]) != 0)
-			sig = 1;
-		else if ((x = s[1] &~ m[1]) != 0)
-			sig = _NSIG_BPW + 1;
-		else
-			break;
-		sig += ffz(~x);
-		break;
-
-	case 1: if ((x = *s &~ *m) != 0)
-			sig = ffz(~x) + 1;
-		break;
-	}
-	
+	unsigned long *s = pending->signal.sig, *m = mask->sig, x;
+	int sig = 0, i;
+	for (i = 0; i < _NSIG_WORDS; i++, s++, m++)
+		if ((x = (*s & ~*m)))
+			sig = fls(x) + i * _NSIG_BPW;
 	return sig;
 }

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux