patch-2.3.40 linux/kernel/signal.c

Next file: linux/lib/inflate.c
Previous file: linux/kernel/sched.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.39/linux/kernel/signal.c linux/kernel/signal.c
@@ -132,56 +132,41 @@
 		int reset = 1;
 
 		/* Collect the siginfo appropriate to this signal.  */
-		if (sig < SIGRTMIN) {
-			/* XXX: As an extension, support queueing exactly
-			   one non-rt signal if SA_SIGINFO is set, so that
-			   we can get more detailed information about the
-			   cause of the signal.  */
-			/* Deciding not to init these couple of fields is
-			   more expensive that just initializing them.  */
+		struct signal_queue *q, **pp;
+		pp = &current->sigqueue;
+		q = current->sigqueue;
+
+		/* Find the one we're interested in ... */
+		for ( ; q ; pp = &q->next, q = q->next)
+			if (q->info.si_signo == sig)
+				break;
+		if (q) {
+			if ((*pp = q->next) == NULL)
+				current->sigqueue_tail = pp;
+			*info = q->info;
+			kmem_cache_free(signal_queue_cachep,q);
+			atomic_dec(&nr_queued_signals);
+
+			/* then see if this signal is still pending. */
+			q = *pp;
+			while (q) {
+				if (q->info.si_signo == sig) {
+					reset = 0;
+					break;
+				}
+				q = q->next;
+			}
+		} else {
+			/* Ok, it wasn't in the queue.  It must have
+			   been sent either by a non-rt mechanism and
+			   we ran out of queue space.  So zero out the
+			   info.  */
 			info->si_signo = sig;
 			info->si_errno = 0;
 			info->si_code = 0;
 			info->si_pid = 0;
 			info->si_uid = 0;
-			SET_UID16(info->si_uid16, 0);
-		} else {
-			struct signal_queue *q, **pp;
-			pp = &current->sigqueue;
-			q = current->sigqueue;
-
-			/* Find the one we're interested in ... */
-			for ( ; q ; pp = &q->next, q = q->next)
-				if (q->info.si_signo == sig)
-					break;
-			if (q) {
-				if ((*pp = q->next) == NULL)
-					current->sigqueue_tail = pp;
-				*info = q->info;
-				kmem_cache_free(signal_queue_cachep,q);
-				atomic_dec(&nr_queued_signals);
-				
-				/* then see if this signal is still pending. */
-				q = *pp;
-				while (q) {
-					if (q->info.si_signo == sig) {
-						reset = 0;
-						break;
-					}
-					q = q->next;
-				}
-			} else {
-				/* Ok, it wasn't in the queue.  It must have
-				   been sent either by a non-rt mechanism and
-				   we ran out of queue space.  So zero out the
-				   info.  */
-				info->si_signo = sig;
-				info->si_errno = 0;
-				info->si_code = 0;
-				info->si_pid = 0;
-				info->si_uid = 0;
-				SET_UID16(info->si_uid16, 0);
-			}
+			SET_SIGINFO_UID16(info->si_uid16, 0);
 		}
 
 		if (reset)
@@ -255,6 +240,8 @@
 {
 	unsigned long flags;
 	int ret;
+	struct signal_queue *q = 0;
+
 
 #if DEBUG_SIG
 printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
@@ -307,43 +294,38 @@
 	if (ignored_signal(sig, t))
 		goto out;
 
-	if (sig < SIGRTMIN) {
-		/* Non-real-time signals are not queued.  */
-		/* XXX: As an extension, support queueing exactly one
-		   non-rt signal if SA_SIGINFO is set, so that we can
-		   get more detailed information about the cause of
-		   the signal.  */
-		if (sigismember(&t->signal, sig))
-			goto out;
-	} else {
-		/* Real-time signals must be queued if sent by sigqueue, or
-		   some other real-time mechanism.  It is implementation
-		   defined whether kill() does so.  We attempt to do so, on
-		   the principle of least surprise, but since kill is not
-		   allowed to fail with EAGAIN when low on memory we just
-		   make sure at least one signal gets delivered and don't
-		   pass on the info struct.  */
-
-		struct signal_queue *q = 0;
-
-		if (atomic_read(&nr_queued_signals) < max_queued_signals) {
-			q = (struct signal_queue *)
-			    kmem_cache_alloc(signal_queue_cachep, GFP_ATOMIC);
-		}
-		
-		if (q) {
-			atomic_inc(&nr_queued_signals);
-			q->next = NULL;
-			*t->sigqueue_tail = q;
-			t->sigqueue_tail = &q->next;
-			switch ((unsigned long) info) {
+	/* Support queueing exactly one non-rt signal, so that we
+	   can get more detailed information about the cause of
+	   the signal. */
+	if (sig < SIGRTMIN && sigismember(&t->signal, sig))
+		goto out;
+
+	/* Real-time signals must be queued if sent by sigqueue, or
+	   some other real-time mechanism.  It is implementation
+	   defined whether kill() does so.  We attempt to do so, on
+	   the principle of least surprise, but since kill is not
+	   allowed to fail with EAGAIN when low on memory we just
+	   make sure at least one signal gets delivered and don't
+	   pass on the info struct.  */
+
+	if (atomic_read(&nr_queued_signals) < max_queued_signals) {
+		q = (struct signal_queue *)
+			kmem_cache_alloc(signal_queue_cachep, GFP_ATOMIC);
+	}
+
+	if (q) {
+		atomic_inc(&nr_queued_signals);
+		q->next = NULL;
+		*t->sigqueue_tail = q;
+		t->sigqueue_tail = &q->next;
+		switch ((unsigned long) info) {
 			case 0:
 				q->info.si_signo = sig;
 				q->info.si_errno = 0;
 				q->info.si_code = SI_USER;
 				q->info.si_pid = current->pid;
 				q->info.si_uid = current->uid;
-				SET_UID16(q->info.si_uid16, current->uid);
+				SET_SIGINFO_UID16(q->info.si_uid16, current->uid);
 				break;
 			case 1:
 				q->info.si_signo = sig;
@@ -351,17 +333,16 @@
 				q->info.si_code = SI_KERNEL;
 				q->info.si_pid = 0;
 				q->info.si_uid = 0;
-				SET_UID16(q->info.si_uid16, 0);
+				SET_SIGINFO_UID16(q->info.si_uid16, 0);
 				break;
 			default:
 				q->info = *info;
 				break;
-			}
-		} else {
-			/* Queue overflow, we have to abort. */
-			ret = -EAGAIN;
-			goto out;
 		}
+	} else {
+		/* Queue overflow, we have to abort. */
+		ret = -EAGAIN;
+		goto out;
 	}
 
 	sigaddset(&t->signal, sig);
@@ -739,6 +720,7 @@
 	 * Invert the set of allowed signals to get those we
 	 * want to block.
 	 */
+	sigdelsetmask(&these, sigmask(SIGKILL)|sigmask(SIGSTOP));
 	signotset(&these);
 
 	if (uts) {
@@ -801,7 +783,7 @@
 	info.si_code = SI_USER;
 	info.si_pid = current->pid;
 	info.si_uid = current->uid;
-	SET_UID16(info.si_uid16, current->uid);
+	SET_SIGINFO_UID16(info.si_uid16, current->uid);
 
 	return kill_something_info(sig, &info, pid);
 }
@@ -875,7 +857,8 @@
 					if (q->info.si_signo != sig)
 						pp = &q->next;
 					else {
-						*pp = q->next;
+						if ((*pp = q->next) == NULL)
+							current->sigqueue_tail = pp;
 						kmem_cache_free(signal_queue_cachep, q);
 						atomic_dec(&nr_queued_signals);
 					}
@@ -922,10 +905,18 @@
 			goto out;
 
 		error = -EINVAL;
-		if (ss_flags & ~SS_DISABLE)
+		/*
+		 *
+		 * Note - this code used to test ss_flags incorrectly
+		 *  	  old code may have been written using ss_flags==0
+		 *	  to mean ss_flags==SS_ONSTACK (as this was the only
+		 *	  way that worked) - this fix preserves that older
+		 *	  mechanism
+		 */
+		if (ss_flags != SS_DISABLE && ss_flags != SS_ONSTACK && ss_flags != 0)
 			goto out;
 
-		if (ss_flags & SS_DISABLE) {
+		if (ss_flags == SS_DISABLE) {
 			ss_size = 0;
 			ss_sp = NULL;
 		} else {

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)