From 34f7242bc8ae873d6bd3289d141bbd64b96318a3 Mon Sep 17 00:00:00 2001 From: kib Date: Fri, 29 May 2015 16:26:08 +0000 Subject: [PATCH] When delivering a signal with default disposition to the thread, tdsigwakeup() increases the priority of the low-priority threads, to give them a chance to be terminated timely. Also, kernel allows user to signal kernel processes. The combined effect is that signalling idle process bump a priority of the selected delivery thread, which starts eating CPU. Check for the delivery thread be an idle thread and do not raise its priority then. The signal delivery to the kernel threads must be opt-in feature. Kernel thread should explicitely declare the ability to handle signals directed to it. E.g., nfsd threads check for signal as an indication of exit request. Most threads do not handle signals at all, and queuing the signal to them causes odd side-effects. Most innocent consequence is the memory leak due to queued ksiginfo, which is never deleted from the sigqueue. Code to prevent even queuing signals to the kernel threads is trivial, but it requires careful examination of each call to kproc/kthread creation to decide should the signalling be allowed. The commit is a stop-gap measure which fixes the immediate case for now. PR: 200493 Reported and tested by: trasz Discussed with: trasz, emaste Sponsored by: The FreeBSD Foundation MFC after: 1 week --- sys/kern/kern_sig.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index b30e1ed75461..5d480604ea98 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -2368,9 +2368,12 @@ tdsigwakeup(struct thread *td, int sig, sig_t action, int intrval) thread_lock(td); /* * Bring the priority of a thread up if we want it to get - * killed in this lifetime. + * killed in this lifetime. Be careful to avoid bumping the + * priority of the idle thread, since we still allow to signal + * kernel processes. */ - if (action == SIG_DFL && (prop & SA_KILL) && td->td_priority > PUSER) + if (action == SIG_DFL && (prop & SA_KILL) != 0 && + td->td_priority > PUSER && !TD_IS_IDLETHREAD(td)) sched_prio(td, PUSER); if (TD_ON_SLEEPQ(td)) { /* @@ -2408,7 +2411,7 @@ tdsigwakeup(struct thread *td, int sig, sig_t action, int intrval) /* * Give low priority threads a better chance to run. */ - if (td->td_priority > PUSER) + if (td->td_priority > PUSER && !TD_IS_IDLETHREAD(td)) sched_prio(td, PUSER); wakeup_swapper = sleepq_abort(td, intrval);