diff --git a/sys/amd64/linux/linux_sysvec.c b/sys/amd64/linux/linux_sysvec.c --- a/sys/amd64/linux/linux_sysvec.c +++ b/sys/amd64/linux/linux_sysvec.c @@ -752,7 +752,8 @@ .sv_setregs = linux_exec_setregs, .sv_fixlimit = NULL, .sv_maxssiz = NULL, - .sv_flags = SV_ABI_LINUX | SV_LP64 | SV_SHP, + .sv_flags = SV_ABI_LINUX | SV_LP64 | SV_SHP | SV_SIG_IGNIGN | + SV_SIG_WAITNDQ, .sv_set_syscall_retval = linux_set_syscall_retval, .sv_fetch_syscall_args = linux_fetch_syscall_args, .sv_syscallnames = NULL, diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c --- a/sys/amd64/linux32/linux32_sysvec.c +++ b/sys/amd64/linux32/linux32_sysvec.c @@ -919,7 +919,8 @@ .sv_setregs = linux_exec_setregs, .sv_fixlimit = linux32_fixlimit, .sv_maxssiz = &linux32_maxssiz, - .sv_flags = SV_ABI_LINUX | SV_ILP32 | SV_IA32 | SV_SHP, + .sv_flags = SV_ABI_LINUX | SV_ILP32 | SV_IA32 | SV_SHP | + SV_SIG_IGNIGN | SV_SIG_WAITNDQ, .sv_set_syscall_retval = linux32_set_syscall_retval, .sv_fetch_syscall_args = linux32_fetch_syscall_args, .sv_syscallnames = NULL, diff --git a/sys/arm64/linux/linux_sysvec.c b/sys/arm64/linux/linux_sysvec.c --- a/sys/arm64/linux/linux_sysvec.c +++ b/sys/arm64/linux/linux_sysvec.c @@ -429,7 +429,8 @@ .sv_setregs = linux_exec_setregs, .sv_fixlimit = NULL, .sv_maxssiz = NULL, - .sv_flags = SV_ABI_LINUX | SV_LP64 | SV_SHP, + .sv_flags = SV_ABI_LINUX | SV_LP64 | SV_SHP | SV_SIG_IGNIGN | + SV_SIG_WAITNDQ, .sv_set_syscall_retval = linux_set_syscall_retval, .sv_fetch_syscall_args = linux_fetch_syscall_args, .sv_syscallnames = NULL, diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c --- a/sys/i386/linux/linux_sysvec.c +++ b/sys/i386/linux/linux_sysvec.c @@ -859,7 +859,8 @@ .sv_setregs = linux_exec_setregs, .sv_fixlimit = NULL, .sv_maxssiz = NULL, - .sv_flags = SV_ABI_LINUX | SV_AOUT | SV_IA32 | SV_ILP32, + .sv_flags = SV_ABI_LINUX | SV_AOUT | SV_IA32 | SV_ILP32 | + SV_SIG_IGNIGN | SV_SIG_WAITNDQ, .sv_set_syscall_retval = linux_set_syscall_retval, .sv_fetch_syscall_args = linux_fetch_syscall_args, .sv_syscallnames = NULL, @@ -897,7 +898,8 @@ .sv_setregs = linux_exec_setregs, .sv_fixlimit = NULL, .sv_maxssiz = NULL, - .sv_flags = SV_ABI_LINUX | SV_IA32 | SV_ILP32 | SV_SHP, + .sv_flags = SV_ABI_LINUX | SV_IA32 | SV_ILP32 | SV_SHP | + SV_SIG_IGNIGN | SV_SIG_WAITNDQ, .sv_set_syscall_retval = linux_set_syscall_retval, .sv_fetch_syscall_args = linux_fetch_syscall_args, .sv_syscallnames = NULL, diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -105,6 +105,11 @@ &kern_kill_on_dbg_exit, 0, "Kill ptraced processes when debugger exits"); +static int kern_wait_dequeue_sigchld = 1; +SYSCTL_INT(_kern, OID_AUTO, wait_dequeue_sigchld, CTLFLAG_RWTUN, + &kern_wait_dequeue_sigchld, 0, + "Dequeue SIGCHLD on wait(2) for live process"); + struct proc * proc_realparent(struct proc *child) { @@ -1207,9 +1212,12 @@ p->p_flag &= ~P_CONTINUED; else p->p_flag |= P_WAITED; - PROC_LOCK(td->td_proc); - sigqueue_take(p->p_ksi); - PROC_UNLOCK(td->td_proc); + if (kern_wait_dequeue_sigchld && + (td->td_proc->p_sysent->sv_flags & SV_SIG_WAITNDQ) == 0) { + PROC_LOCK(td->td_proc); + sigqueue_take(p->p_ksi); + PROC_UNLOCK(td->td_proc); + } } sx_xunlock(&proctree_lock); if (siginfo != NULL) { diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -163,6 +163,12 @@ "Fetch sigfastblock word on each syscall entry for proper " "blocking semantic"); +static bool kern_sig_ign_ign = true; +SYSCTL_BOOL(_kern, OID_AUTO, sig_ign_ign, CTLFLAG_RWTUN, + &kern_sig_ign_ign, 0, + "Ignore ignored signals on delivery, otherwise queue them to " + "the target queue"); + SYSINIT(signal, SI_SUB_P1003_1B, SI_ORDER_FIRST+3, sigqueue_start, NULL); /* @@ -1285,6 +1291,9 @@ PROC_LOCK(p); saved_mask = td->td_sigmask; SIGSETNAND(td->td_sigmask, waitset); + if ((p->p_sysent->sv_flags & SV_SIG_IGNIGN) != 0 || + !kern_sig_ign_ign) + td->td_pflags2 |= TDP2_SIGWAIT; for (;;) { mtx_lock(&ps->ps_mtx); sig = cursig(td); @@ -1329,15 +1338,13 @@ error = msleep(ps, &p->p_mtx, PPAUSE|PCATCH, "sigwait", timo); - if (timeout != NULL) { - if (error == ERESTART) { - /* Timeout can not be restarted. */ - error = EINTR; - } else if (error == EAGAIN) { - /* We will calculate timeout by ourself. */ - error = 0; - } - } + /* The syscalls can not be restarted. */ + if (error == ERESTART) + error = EINTR; + + /* We will calculate timeout by ourself. */ + if (timeout != NULL && error == EAGAIN) + error = 0; /* * If PTRACE_SCE or PTRACE_SCX were set after @@ -1349,6 +1356,7 @@ if (error == 0 && (p->p_ptevents & PTRACE_SYSCALL) != 0) traced = true; } + td->td_pflags2 &= ~TDP2_SIGWAIT; new_block = saved_mask; SIGSETNAND(new_block, td->td_sigmask); @@ -2197,22 +2205,25 @@ SDT_PROBE3(proc, , , signal__send, td, p, sig); /* - * If the signal is being ignored, - * then we forget about it immediately. - * (Note: we don't set SIGCONT in ps_sigignore, - * and if it is set to SIG_IGN, - * action will be SIG_DFL here.) + * If the signal is being ignored, then we forget about it + * immediately, except when the target process executes + * sigwait(). (Note: we don't set SIGCONT in ps_sigignore, + * and if it is set to SIG_IGN, action will be SIG_DFL here.) */ mtx_lock(&ps->ps_mtx); if (SIGISMEMBER(ps->ps_sigignore, sig)) { - SDT_PROBE3(proc, , , signal__discard, td, p, sig); + if (kern_sig_ign_ign && + (p->p_sysent->sv_flags & SV_SIG_IGNIGN) == 0) { + SDT_PROBE3(proc, , , signal__discard, td, p, sig); - mtx_unlock(&ps->ps_mtx); - if (ksi && (ksi->ksi_flags & KSI_INS)) - ksiginfo_tryfree(ksi); - return (ret); - } - if (SIGISMEMBER(td->td_sigmask, sig)) + mtx_unlock(&ps->ps_mtx); + if (ksi && (ksi->ksi_flags & KSI_INS)) + ksiginfo_tryfree(ksi); + return (ret); + } else { + action = SIG_CATCH; + } + } else if (SIGISMEMBER(td->td_sigmask, sig)) action = SIG_HOLD; else if (SIGISMEMBER(ps->ps_sigcatch, sig)) action = SIG_CATCH; @@ -2947,11 +2958,13 @@ } /* - * We should see pending but ignored signals - * only if P_TRACED was on when they were posted. + * We should allow pending but ignored signals below + * only if there is sigwait() active, or P_TRACED was + * on when they were posted. */ if (SIGISMEMBER(ps->ps_sigignore, sig) && - (p->p_flag & P_TRACED) == 0) { + (p->p_flag & P_TRACED) == 0 && + (td->td_pflags2 & TDP2_SIGWAIT) == 0) { sigqueue_delete(&td->td_sigqueue, sig); sigqueue_delete(&p->p_sigqueue, sig); continue; @@ -3063,10 +3076,11 @@ PROC_SUNLOCK(p); mtx_lock(&ps->ps_mtx); goto next; - } else if (prop & SIGPROP_IGNORE) { + } else if ((prop & SIGPROP_IGNORE) != 0 && + (td->td_pflags2 & TDP2_SIGWAIT) == 0) { /* - * Except for SIGCONT, shouldn't get here. - * Default action is to ignore; drop it. + * Default action is to ignore; drop it if + * not in sigtimedwait(). */ break; /* == ignore */ } else @@ -3074,15 +3088,10 @@ /*NOTREACHED*/ case (intptr_t)SIG_IGN: - /* - * Masking above should prevent us ever trying - * to take action on an ignored signal other - * than SIGCONT, unless process is traced. - */ - if ((prop & SIGPROP_CONT) == 0 && - (p->p_flag & P_TRACED) == 0) - printf("issignal\n"); - break; /* == ignore */ + if ((td->td_pflags2 & TDP2_SIGWAIT) == 0) + break; /* == ignore */ + else + return (sig); default: /* diff --git a/sys/sys/proc.h b/sys/sys/proc.h --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -529,6 +529,7 @@ #define TDP2_SBPAGES 0x00000001 /* Owns sbusy on some pages */ #define TDP2_COMPAT32RB 0x00000002 /* compat32 ABI for robust lists */ #define TDP2_ACCT 0x00000004 /* Doing accounting */ +#define TDP2_SIGWAIT 0x00000008 /* Ignore ignored signals */ /* * Reasons that the current thread can not be run yet. diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h --- a/sys/sys/sysent.h +++ b/sys/sys/sysent.h @@ -161,6 +161,8 @@ #define SV_TIMEKEEP 0x040000 /* Shared page timehands. */ #define SV_ASLR 0x080000 /* ASLR allowed. */ #define SV_RNG_SEED_VER 0x100000 /* random(4) reseed generation. */ +#define SV_SIG_IGNIGN 0x200000 /* Do not ignore ignored signals */ +#define SV_SIG_WAITNDQ 0x400000 /* Wait does not dequeue SIGCHLD */ #define SV_ABI_MASK 0xff #define SV_PROC_FLAG(p, x) ((p)->p_sysent->sv_flags & (x))