From owner-svn-src-all@freebsd.org Sun Jun 26 20:07:26 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 108C5B8185B; Sun, 26 Jun 2016 20:07:26 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id DF8CC2AA3; Sun, 26 Jun 2016 20:07:25 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u5QK7PTu042641; Sun, 26 Jun 2016 20:07:25 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u5QK7OG0042634; Sun, 26 Jun 2016 20:07:24 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201606262007.u5QK7OG0042634@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Sun, 26 Jun 2016 20:07:24 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r302215 - in head/sys: fs/fifofs kern sys X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.22 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: Sun, 26 Jun 2016 20:07:26 -0000 Author: kib Date: Sun Jun 26 20:07:24 2016 New Revision: 302215 URL: https://svnweb.freebsd.org/changeset/base/302215 Log: Rewrite sigdeferstop(9) and sigallowstop(9) into more flexible framework allowing to set the suspension policy for the dynamic block. Extend the currently possible policies of stopping on interruptible sleeps and ignoring such sleeps by two more: do not suspend at interruptible sleeps, but interrupt them with either EINTR or ERESTART. Reviewed by: jilles Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 2 weeks Approved by: re (gjb) Modified: head/sys/fs/fifofs/fifo_vnops.c head/sys/kern/kern_sig.c head/sys/kern/kern_thread.c head/sys/kern/subr_trap.c head/sys/sys/mount.h head/sys/sys/proc.h head/sys/sys/signalvar.h Modified: head/sys/fs/fifofs/fifo_vnops.c ============================================================================== --- head/sys/fs/fifofs/fifo_vnops.c Sun Jun 26 18:43:42 2016 (r302214) +++ head/sys/fs/fifofs/fifo_vnops.c Sun Jun 26 20:07:24 2016 (r302215) @@ -194,11 +194,10 @@ fifo_open(ap) if ((ap->a_mode & FREAD) && fip->fi_writers == 0) { gen = fip->fi_wgen; VOP_UNLOCK(vp, 0); - stops_deferred = sigallowstop(); + stops_deferred = sigdeferstop(SIGDEFERSTOP_OFF); error = msleep(&fip->fi_readers, PIPE_MTX(fpipe), PDROP | PCATCH | PSOCK, "fifoor", 0); - if (stops_deferred) - sigdeferstop(); + sigallowstop(stops_deferred); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); if (error != 0 && gen == fip->fi_wgen) { fip->fi_readers--; @@ -222,11 +221,10 @@ fifo_open(ap) if ((ap->a_mode & FWRITE) && fip->fi_readers == 0) { gen = fip->fi_rgen; VOP_UNLOCK(vp, 0); - stops_deferred = sigallowstop(); + stops_deferred = sigdeferstop(SIGDEFERSTOP_OFF); error = msleep(&fip->fi_writers, PIPE_MTX(fpipe), PDROP | PCATCH | PSOCK, "fifoow", 0); - if (stops_deferred) - sigdeferstop(); + sigallowstop(stops_deferred); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); if (error != 0 && gen == fip->fi_rgen) { fip->fi_writers--; Modified: head/sys/kern/kern_sig.c ============================================================================== --- head/sys/kern/kern_sig.c Sun Jun 26 18:43:42 2016 (r302214) +++ head/sys/kern/kern_sig.c Sun Jun 26 20:07:24 2016 (r302215) @@ -2596,41 +2596,81 @@ tdsigcleanup(struct thread *td) } +static int +sigdeferstop_curr_flags(int cflags) +{ + + MPASS((cflags & (TDF_SEINTR | TDF_SERESTART)) == 0 || + (cflags & TDF_SBDRY) != 0); + return (cflags & (TDF_SBDRY | TDF_SEINTR | TDF_SERESTART)); +} + /* - * Defer the delivery of SIGSTOP for the current thread. Returns true - * if stops were deferred and false if they were already deferred. + * Defer the delivery of SIGSTOP for the current thread, according to + * the requested mode. Returns previous flags, which must be restored + * by sigallowstop(). + * + * TDF_SBDRY, TDF_SEINTR, and TDF_SERESTART flags are only set and + * cleared by the current thread, which allow the lock-less read-only + * accesses below. */ int -sigdeferstop(void) +sigdeferstop(int mode) { struct thread *td; + int cflags, nflags; td = curthread; - if (td->td_flags & TDF_SBDRY) - return (0); - thread_lock(td); - td->td_flags |= TDF_SBDRY; - thread_unlock(td); - return (1); + cflags = sigdeferstop_curr_flags(td->td_flags); + switch (mode) { + case SIGDEFERSTOP_NOP: + nflags = cflags; + break; + case SIGDEFERSTOP_OFF: + nflags = 0; + break; + case SIGDEFERSTOP_SILENT: + nflags = (cflags | TDF_SBDRY) & ~(TDF_SEINTR | TDF_SERESTART); + break; + case SIGDEFERSTOP_EINTR: + nflags = (cflags | TDF_SBDRY | TDF_SEINTR) & ~TDF_SERESTART; + break; + case SIGDEFERSTOP_ERESTART: + nflags = (cflags | TDF_SBDRY | TDF_SERESTART) & ~TDF_SEINTR; + break; + default: + panic("sigdeferstop: invalid mode %x", mode); + break; + } + if (cflags != nflags) { + thread_lock(td); + td->td_flags = (td->td_flags & ~cflags) | nflags; + thread_unlock(td); + } + return (cflags); } /* - * Permit the delivery of SIGSTOP for the current thread. This does - * not immediately suspend if a stop was posted. Instead, the thread - * will suspend either via ast() or a subsequent interruptible sleep. + * Restores the STOP handling mode, typically permitting the delivery + * of SIGSTOP for the current thread. This does not immediately + * suspend if a stop was posted. Instead, the thread will suspend + * either via ast() or a subsequent interruptible sleep. */ -int -sigallowstop(void) +void +sigallowstop(int prev) { struct thread *td; - int prev; + int cflags; + KASSERT((prev & ~(TDF_SBDRY | TDF_SEINTR | TDF_SERESTART)) == 0, + ("sigallowstop: incorrect previous mode %x", prev)); td = curthread; - thread_lock(td); - prev = (td->td_flags & TDF_SBDRY) != 0; - td->td_flags &= ~TDF_SBDRY; - thread_unlock(td); - return (prev); + cflags = sigdeferstop_curr_flags(td->td_flags); + if (cflags != prev) { + thread_lock(td); + td->td_flags = (td->td_flags & ~cflags) | prev; + thread_unlock(td); + } } /* Modified: head/sys/kern/kern_thread.c ============================================================================== --- head/sys/kern/kern_thread.c Sun Jun 26 18:43:42 2016 (r302214) +++ head/sys/kern/kern_thread.c Sun Jun 26 20:07:24 2016 (r302215) @@ -894,7 +894,7 @@ thread_suspend_check(int return_instead) { struct thread *td; struct proc *p; - int wakeup_swapper; + int wakeup_swapper, r; td = curthread; p = td->td_proc; @@ -927,7 +927,21 @@ thread_suspend_check(int return_instead) if ((td->td_flags & TDF_SBDRY) != 0) { KASSERT(return_instead, ("TDF_SBDRY set for unsafe thread_suspend_check")); - return (0); + switch (td->td_flags & (TDF_SEINTR | TDF_SERESTART)) { + case 0: + r = 0; + break; + case TDF_SEINTR: + r = EINTR; + break; + case TDF_SERESTART: + r = ERESTART; + break; + default: + panic("both TDF_SEINTR and TDF_SERESTART"); + break; + } + return (r); } /* Modified: head/sys/kern/subr_trap.c ============================================================================== --- head/sys/kern/subr_trap.c Sun Jun 26 18:43:42 2016 (r302214) +++ head/sys/kern/subr_trap.c Sun Jun 26 20:07:24 2016 (r302215) @@ -160,7 +160,7 @@ userret(struct thread *td, struct trapfr ("userret: Returning with with pinned thread")); KASSERT(td->td_vp_reserv == 0, ("userret: Returning while holding vnode reservation")); - KASSERT((td->td_flags & TDF_SBDRY) == 0, + KASSERT((td->td_flags & (TDF_SBDRY | TDF_SEINTR | TDF_SERESTART)) == 0, ("userret: Returning with stop signals deferred")); KASSERT(td->td_su == NULL, ("userret: Returning with SU cleanup request not handled")); Modified: head/sys/sys/mount.h ============================================================================== --- head/sys/sys/mount.h Sun Jun 26 18:43:42 2016 (r302214) +++ head/sys/sys/mount.h Sun Jun 26 20:07:24 2016 (r302215) @@ -653,15 +653,15 @@ vfs_statfs_t __vfs_statfs; #define VFS_PROLOGUE(MP) do { \ struct mount *mp__; \ - int _enable_stops; \ + int _prev_stops; \ \ mp__ = (MP); \ - _enable_stops = (mp__ != NULL && \ - (mp__->mnt_vfc->vfc_flags & VFCF_SBDRY) && sigdeferstop()) + _prev_stops = sigdeferstop((mp__ != NULL && \ + (mp__->mnt_vfc->vfc_flags & VFCF_SBDRY) != 0) ? \ + SIGDEFERSTOP_SILENT : SIGDEFERSTOP_NOP); #define VFS_EPILOGUE(MP) \ - if (_enable_stops) \ - sigallowstop(); \ + sigallowstop(_prev_stops); \ } while (0) #define VFS_MOUNT(MP) ({ \ Modified: head/sys/sys/proc.h ============================================================================== --- head/sys/sys/proc.h Sun Jun 26 18:43:42 2016 (r302214) +++ head/sys/sys/proc.h Sun Jun 26 20:07:24 2016 (r302215) @@ -395,9 +395,9 @@ do { \ #define TDF_NEEDRESCHED 0x00010000 /* Thread needs to yield. */ #define TDF_NEEDSIGCHK 0x00020000 /* Thread may need signal delivery. */ #define TDF_NOLOAD 0x00040000 /* Ignore during load avg calculations. */ -#define TDF_UNUSED19 0x00080000 /* --available-- */ +#define TDF_SERESTART 0x00080000 /* ERESTART on stop attempts. */ #define TDF_THRWAKEUP 0x00100000 /* Libthr thread must not suspend itself. */ -#define TDF_UNUSED21 0x00200000 /* --available-- */ +#define TDF_SEINTR 0x00200000 /* EINTR on stop attempts. */ #define TDF_SWAPINREQ 0x00400000 /* Swapin request due to wakeup. */ #define TDF_UNUSED23 0x00800000 /* --available-- */ #define TDF_SCHED0 0x01000000 /* Reserved for scheduler private use */ Modified: head/sys/sys/signalvar.h ============================================================================== --- head/sys/sys/signalvar.h Sun Jun 26 18:43:42 2016 (r302214) +++ head/sys/sys/signalvar.h Sun Jun 26 20:07:24 2016 (r302215) @@ -325,9 +325,21 @@ extern struct mtx sigio_lock; #define SIGPROCMASK_PROC_LOCKED 0x0002 #define SIGPROCMASK_PS_LOCKED 0x0004 +/* + * Modes for sigdeferstop(). Manages behaviour of + * thread_suspend_check() in the region delimited by + * sigdeferstop()/sigallowstop(). Must be restored to + * SIGDEFERSTOP_OFF before returning to userspace. + */ +#define SIGDEFERSTOP_NOP 0 /* continue doing whatever is done now */ +#define SIGDEFERSTOP_OFF 1 /* stop ignoring STOPs */ +#define SIGDEFERSTOP_SILENT 2 /* silently ignore STOPs */ +#define SIGDEFERSTOP_EINTR 3 /* ignore STOPs, return EINTR */ +#define SIGDEFERSTOP_ERESTART 4 /* ignore STOPs, return ERESTART */ + int cursig(struct thread *td); -int sigdeferstop(void); -int sigallowstop(void); +int sigdeferstop(int mode); +void sigallowstop(int prev); void execsigs(struct proc *p); void gsignal(int pgid, int sig, ksiginfo_t *ksi); void killproc(struct proc *p, char *why);