From owner-freebsd-current@FreeBSD.ORG Fri Jan 25 20:01:22 2013 Return-Path: Delivered-To: freebsd-current@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 0754C7D9; Fri, 25 Jan 2013 20:01:22 +0000 (UTC) (envelope-from rysto32@gmail.com) Received: from mail-ob0-f182.google.com (mail-ob0-f182.google.com [209.85.214.182]) by mx1.freebsd.org (Postfix) with ESMTP id 799F969C; Fri, 25 Jan 2013 20:01:21 +0000 (UTC) Received: by mail-ob0-f182.google.com with SMTP id uo13so908692obb.41 for ; Fri, 25 Jan 2013 12:01:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:x-received:date:message-id:subject:from:to:cc :content-type; bh=HHblxSDoBl+9CVwy3jKhoDMaH/fz0niloOu23Dmd1yE=; b=Qr4tU2ad7P+j0Jyz+Pqp2j/v2+TWqEn998hBwkstvvTH9u/xTY2mXjA1puH2ECRSmQ IdI269lVgzuRNwmzTtk0Sd2iCROAwbWhW1Ho2W20H9IqEJ18Dc+lMl8d/wQCGgxOdaQK wXbouUvBYyI2uu5sbPAPb8SErkGzO9leqMe+f5msgcqP8Mapyydqu2oafw1y+kEaObuA dusqX93BhBkziRAESV6sU3o69hZr9E9L41RP9g2r188l7o56rngXnJxMWBpa5gK8LfLl R32HD0sphiQBK9rh+v4FZe6KqVNgl4Lv6vkvpBJrLDgDssaQmMUJYcjlDR2ZmykMEXVx OtbQ== MIME-Version: 1.0 X-Received: by 10.182.92.70 with SMTP id ck6mr5481463obb.46.1359144074803; Fri, 25 Jan 2013 12:01:14 -0800 (PST) Received: by 10.76.128.68 with HTTP; Fri, 25 Jan 2013 12:01:14 -0800 (PST) Date: Fri, 25 Jan 2013 15:01:14 -0500 Message-ID: Subject: Why don't we check for preemption when we unlend priority? From: Ryan Stone To: FreeBSD Current Content-Type: text/plain; charset=ISO-8859-1 X-Content-Filtered-By: Mailman/MimeDel 2.1.14 Cc: Attilio Rao X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 25 Jan 2013 20:01:22 -0000 I'm having a problem where userland threads are running with a loaned (via mutex priority propagation) priority even after they have released the mutex. This is causing the low-priority userland thread to starve high-priority interrupt threads. One scenario is(which I am seeing on FreeBSD 8.2, but the priority lending code does not seem to have changed in HEAD): 1) I have several swi threads that are pulling packets off of interfaces and forwarding them. Each swi thread is pinned to a CPU. 2) A remote user initiates an scp of a large file to this machine. 3) sshd (which handles the scp) takes a mutex on its socket 4) An interrupt or taskqueue thread belonging to the driver that is receiving the scp traffic tries to take the same mutex. It can't and so it lends its priority to the sshd thread. 5) My swi thread is woken. It is pinned to the same CPU as sshd, but it has a lower priority than the lent priority, so it is placed on the runqueue. 6) The sshd thread releases the mutex. sched_unlend_prio is called to set its priority back to a normal user priority. However, it does not check whether any higher-priority threads are waiting in the runqueue. 7) The sshd thread is allowed to run for its full quantum (100ms). This is easily long enough for my swi thread to start and I drop packets. This is similar to a problem fixed by jhb@ a while ago, which was discussed here: http://lists.freebsd.org/pipermail/freebsd-arch/2010-December/010835.html However in my case it is a thread at an ithread priority that is started, not a userland realtime thread. I don't see why sched_unlend_prio can't check for preemption. I know that in jhb's case we didn't want to check for preemption in userret for performance reasons. In my case, sched_unlend_prio already holds the relevant scheduler lock (and hopefully mutex contention is a rare case anyway), so I don't see that the same performance argument applies. The following proof-of-concept patch for ULE resolves the starvation for me. Any comments? diff --git a/sys/kern/sched_ule.c b/sys/kern/sched_ule.c index 01559ee..2659614 100644 --- a/sys/kern/sched_ule.c +++ b/sys/kern/sched_ule.c @@ -1586,6 +1586,22 @@ sched_pctcpu_update(struct td_sched *ts) ts->ts_ftick = ts->ts_ltick - SCHED_TICK_TARG; } +static void +sched_check_preempt(struct tdq *tdq, struct thread *td) +{ + + KASSERT(TD_IS_RUNNING(td), ("thread is not running")); + TDQ_LOCK_ASSERT(tdq, MA_OWNED); + KASSERT(tdq == TDQ_CPU(td->td_sched->ts_cpu), ("tdq does not td")); + + if (tdq == TDQ_SELF()) { + if (td->td_priority > tdq->tdq_lowpri && + sched_shouldpreempt(tdq->tdq_lowpri, td->td_priority, 0)) + td->td_owepreempt = 1; + } else + tdq_notify(tdq, td); +} + /* * Adjust the priority of a thread. Move it to the appropriate run-queue * if necessary. This is the back-end for several priority related @@ -1635,8 +1651,10 @@ sched_thread_priority(struct thread *td, u_char prio) td->td_priority = prio; if (prio < tdq->tdq_lowpri) tdq->tdq_lowpri = prio; - else if (tdq->tdq_lowpri == oldpri) + else if (tdq->tdq_lowpri == oldpri) { tdq_setlowpri(tdq, td); + sched_check_preempt(tdq, td); + } return; } td->td_priority = prio;