Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 10 Nov 2009 11:46:54 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r199136 - in head/sys: kern sys
Message-ID:  <200911101146.nAABksqs058013@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Tue Nov 10 11:46:53 2009
New Revision: 199136
URL: http://svn.freebsd.org/changeset/base/199136

Log:
  In r198506, kern_sigsuspend() started doing cursig/postsig loop to make
  sure that a signal was delivered to the thread before returning from
  syscall. Signal delivery puts new return frame on the user stack, and
  modifies trap frame to enter signal handler. As a consequence, syscall
  return code sets EINTR as error return for signal frame, instead of the
  syscall return.
  
  Also, for ia64, due to different registers layout for those two kind of
  frames, usermode sigsegfaulted when returned from signal handler.
  
  Use newly-introduced cpu_set_syscall_retval(9) to set syscall result,
  and return EJUSTRETURN from kern_sigsuspend() to prevent syscall return
  code from modifying this frame [1].
  
  Another issue is that pending SIGCONT might be cancelled by SIGSTOP,
  causing postsig() not to deliver any catched signal [2]. Modify
  postsig() to return 1 if signal was posted, and 0 otherwise, and use
  this in the kern_sigsuspend loop.
  
  Proposed by:	marcel [1]
  Noted by:	davidxu [2]
  Reviewed by:	marcel, davidxu
  MFC after:	1 month

Modified:
  head/sys/kern/kern_sig.c
  head/sys/sys/signalvar.h

Modified: head/sys/kern/kern_sig.c
==============================================================================
--- head/sys/kern/kern_sig.c	Tue Nov 10 11:43:07 2009	(r199135)
+++ head/sys/kern/kern_sig.c	Tue Nov 10 11:46:53 2009	(r199136)
@@ -1471,21 +1471,19 @@ kern_sigsuspend(struct thread *td, sigse
 	 * thread. But sigsuspend should return only on signal
 	 * delivery.
 	 */
+	cpu_set_syscall_retval(td, EINTR);
 	for (has_sig = 0; !has_sig;) {
 		while (msleep(&p->p_sigacts, &p->p_mtx, PPAUSE|PCATCH, "pause",
 			0) == 0)
 			/* void */;
 		thread_suspend_check(0);
 		mtx_lock(&p->p_sigacts->ps_mtx);
-		while ((sig = cursig(td, SIG_STOP_ALLOWED)) != 0) {
-			postsig(sig);
-			has_sig = 1;
-		}
+		while ((sig = cursig(td, SIG_STOP_ALLOWED)) != 0)
+			has_sig += postsig(sig);
 		mtx_unlock(&p->p_sigacts->ps_mtx);
 	}
 	PROC_UNLOCK(p);
-	/* always return EINTR rather than ERESTART... */
-	return (EINTR);
+	return (EJUSTRETURN);
 }
 
 #ifdef COMPAT_43	/* XXX - COMPAT_FBSD3 */
@@ -2670,7 +2668,7 @@ thread_stopped(struct proc *p)
  * Take the action for the specified signal
  * from the current set of pending signals.
  */
-void
+int
 postsig(sig)
 	register int sig;
 {
@@ -2689,7 +2687,7 @@ postsig(sig)
 	ksiginfo_init(&ksi);
 	if (sigqueue_get(&td->td_sigqueue, sig, &ksi) == 0 &&
 	    sigqueue_get(&p->p_sigqueue, sig, &ksi) == 0)
-		return;
+		return (0);
 	ksi.ksi_signo = sig;
 	if (ksi.ksi_code == SI_TIMER)
 		itimer_accept(p, ksi.ksi_timerid, &ksi);
@@ -2757,6 +2755,7 @@ postsig(sig)
 		}
 		(*p->p_sysent->sv_sendsig)(action, &ksi, &returnmask);
 	}
+	return (1);
 }
 
 /*

Modified: head/sys/sys/signalvar.h
==============================================================================
--- head/sys/sys/signalvar.h	Tue Nov 10 11:43:07 2009	(r199135)
+++ head/sys/sys/signalvar.h	Tue Nov 10 11:46:53 2009	(r199136)
@@ -330,7 +330,7 @@ void	gsignal(int pgid, int sig);
 void	killproc(struct proc *p, char *why);
 void	pgsigio(struct sigio **, int signum, int checkctty);
 void	pgsignal(struct pgrp *pgrp, int sig, int checkctty);
-void	postsig(int sig);
+int	postsig(int sig);
 void	psignal(struct proc *p, int sig);
 int	psignal_event(struct proc *p, struct sigevent *, ksiginfo_t *);
 struct sigacts *sigacts_alloc(void);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200911101146.nAABksqs058013>