From owner-freebsd-current Sun Feb 24 17:38:10 2002 Delivered-To: freebsd-current@freebsd.org Received: from apollo.backplane.com (apollo.backplane.com [216.240.41.2]) by hub.freebsd.org (Postfix) with ESMTP id 2943A37B400; Sun, 24 Feb 2002 17:38:06 -0800 (PST) Received: (from dillon@localhost) by apollo.backplane.com (8.11.6/8.9.1) id g1P1bXq27219; Sun, 24 Feb 2002 17:37:33 -0800 (PST) (envelope-from dillon) Date: Sun, 24 Feb 2002 17:37:33 -0800 (PST) From: Matthew Dillon Message-Id: <200202250137.g1P1bXq27219@apollo.backplane.com> To: Andrew Gallatin Cc: John Baldwin , dfr@nlsystems.com, current@FreeBSD.ORG Subject: Re: Patch for critical_enter()/critical_exit() & interrupt assembly revamp, please review! References: <20020224131027.I31343-100000@gamplex.bde.org> <200202241912.g1OJCMx95238@apollo.backplane.com> <15481.36444.52026.935742@grasshopper.cs.duke.edu> Sender: owner-freebsd-current@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG :I think you're making critical_enter()/critical_exit() cheaper by not :actually messing with the interrupt hardware when they're called. :Very much like what we do in 4-stable. : :Instead, you set/clear a per-cpu flag (or incr/decr a counter). If an :interrupt comes in when you're inside a critical section, you make :note of it & mask interrupts on that cpu. In critical_exit(), :you run the interrupt handler if there's a pending interrupt, and :unmask interrupts. If there's not a pending interrupt, you just clear :the flag (or devrement a counter). : :Is that basically it? Right. And it turns out to be a whole lot easier to do in -current because we do not have the _cpl baggage. Basically critical_enter() devolves down into: ++td->td_critnest And critical_exit() devolves down into: if (--td->td_critnest == 0 && PCPU_GET(int_pending)) _deal_with_interupts_marked_pending() As we found with the lazy spl()s in -stable, this is a huge win-win situation because no interrupts typically occur while one is in short-lived critical sections. On -current, critical sections are for spin locks (i.e. mainly the sched_lock) and in a few other tiny pieces of code and that is pretty much it. It is a far better situation then the massive use of spl*()'s we see in -stable and once Giant is gone it is going to be pretty awesome. :If so, I'm wondering if this is even possible on alpha, where we don't :have direct access to the hardware. However, according to the psuedo :code for rti in the Brown book, munging with the saved PSL in :trapframe to set the IPL should work. Hmm.. : :Drew Well, on IA32 there are effectively two types of interrupts (edge and level triggered), and three interrupt masks (the processor interrupt disable, a master bit mask, and then the per-device masks), and two ways of handling interrupts (as a scheduled interrupt thread or as a 'fast' interrupt). Note that the masking requirement is already part and parcel in -current because most interrupts are now scheduled. The hardware interrupt routine must schedule the interrupt thread and then mask the interrupt since it is not dealing with it right then and there and must be able to return to whatever was running before. The interrupt thread will unmask the interrupt when it is through processing it. But *which* mask one is able to use determines how efficiently one can write critical_enter() and critical_exit(). On IA32 we can use the master bit mask instead of the processor interrupt disable which allows the optimization you see in this patch set. -- On alpha if you are only able to use the process interrupt disable you can still optimizatize critical_enter() and critical_exit(). That is, you can do this: critical_enter(): ++td->td_critnest; critical_exit() if (--td->td_critnest == 0 && PCPU_GET(int_pending)) { PCPU_SET(int_pending, 0); if (PCPU_GET(ipending)) deal_with_pending_edge_triggered_ints(); enable_hardware_interrupts(); (level triggered ints will immediately cause an interrupt which, since critnest is 0, can now be taken) } hard interrupt vector code: if (curthread->td_critnest) { Save any edge triggered interrupts to a bitmap somewhere (i.e. ipending |= 1 << irq_that_was_taken). adjust return frame such that the restored PSL has interrupts disabled so it does not immediately re-enter the hardware interrupt vector code. } As you can see, it should be possible to make critical_enter() and critical_exit() streamlined even on architectures where you may not have direct access to interrupt masks. In fact, I considered doing exactly this for the I386 but decided that it was cleaner to mask level interrupts and throw everything into the same ipending hopper. -Matt Matthew Dillon To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message