From owner-svn-src-all@FreeBSD.ORG Tue Nov 10 11:46:55 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 2A8841065670; Tue, 10 Nov 2009 11:46:54 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id D90198FC0C; Tue, 10 Nov 2009 11:46:54 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id nAABksWF058016; Tue, 10 Nov 2009 11:46:54 GMT (envelope-from kib@svn.freebsd.org) Received: (from kib@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id nAABksqs058013; Tue, 10 Nov 2009 11:46:54 GMT (envelope-from kib@svn.freebsd.org) Message-Id: <200911101146.nAABksqs058013@svn.freebsd.org> From: Konstantin Belousov Date: Tue, 10 Nov 2009 11:46:54 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r199136 - in head/sys: kern sys X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 10 Nov 2009 11:46:55 -0000 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);