Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 29 Nov 2001 06:31:16 -0800
From:      Luigi Rizzo <rizzo@aciri.org>
To:        Bruce Evans <bde@zeta.org.au>
Cc:        net@FreeBSD.ORG
Subject:   Re: Revised polling code for STABLE
Message-ID:  <20011129063116.B19430@iguana.aciri.org>
In-Reply-To: <20011129222256.W1389-100000@gamplex.bde.org>
References:  <20011126115704.L88153@iguana.aciri.org> <20011129222256.W1389-100000@gamplex.bde.org>

next in thread | previous in thread | raw e-mail | index | archive | help
Bruce, thanks for the feedback.

Re. the second issue:

the code was placed in kern_clock.c just as a placeholder (and
because i needed to touch a couple of places in that file, i tried
to minimize the number of files affected by the patch). But surely,
the core of the code can go somewhere else, e.g. in net/
(i have had it for a long time in if_ethersubr.c), or maybe
even in a separate file, as you like.
The call to update_poll_threshold() however needs to be done by
either hardclock() or statclock() (i am experimenting with that
right now) because the purpose is to sample what the CPU is doing
when we get that particular interrupt.

I do not know how/if I can replace the schednetisr() with an ordinary timeout:
i need the handler to be invoked as soon as possible after the
clock ticks, as the task it performs are as urgent as interrupt requests.
Certainly I do not want it to be run after other netisr handlers
(this is also why NETISR_POLL is lower than any other NETISR, so
the corresponding handler is called first).
It looked like the schednetisr() was the simplest (one-line change) and
more effective way to achieve this, if you know of other ways involving
timeouts please let me know.

Re. the first one, yes the code might probably benefit from
a bit of rearrangement, such as below

    #ifdef     XORP_ETHER_POLLING
	call	_idle_poll
    #else
        call    _vm_page_zero_idle
    #endif
        testl   %eax, %eax
        jnz     idle_loop

with idle_poll being

	int idle_poll() {
	{
		idle_done=1;
		if (poll_handlers > 0) {
		    int s = splimp();
		    __asm __volatile("sti" : : : "memory");
		    retval = ether_poll(poll_burst);
		    __asm __volatile("cli" : : : "memory");
		    splx(s);
		    vm_page_zero_idle();
		    return 1;
		} else
		    return vm_page_zero_idle();
	}

The thing is, with polling you cannot halt the CPU if there are handlers
registered for polling. You can try and deregister polling on
interfaces which are idle, which then should be handled correctly
by the above function.

Does the above make sense ?

	cheers
	luigi


On Thu, Nov 29, 2001 at 11:26:20PM +1100, Bruce Evans wrote:
> > On Mon, 26 Nov 2001, Luigi Rizzo wrote:
> >
> > > [Bcc to -stable in case someone is interested there]
> > >
> > > Attached you can find the latest version of the polling code
> > > for STABLE (which is useful to make boxes much more robust
> > > to attacks and have much better responsiveness under [over]load).
> > > ...
> > Index: sys/i386/i386/swtch.s
> > ===================================================================
> > RCS file: /home/xorpc/u2/freebsd/src/sys/i386/i386/swtch.s,v
> > retrieving revision 1.89.2.4
> > diff -u -r1.89.2.4 swtch.s
> > --- sys/i386/i386/swtch.s	2001/07/26 02:29:10	1.89.2.4
> > +++ sys/i386/i386/swtch.s	2001/10/26 21:54:19
> > @@ -246,6 +246,17 @@
> >  	call	_procrunnable
> >  	testl	%eax,%eax
> >  	CROSSJUMP(jnz, sw1a, jz)
> > +#ifdef	XORP_ETHER_POLLING
> > +	incl	_idle_done
> > +	pushl	_poll_burst
> > +	call	_ether_poll
> > +	addl	$4,%esp
> > +	sti
> > +	nop
> > +	cli
> > +	testl   %eax, %eax
> > +	jnz     idle_loop
> > +#endif
> >  	call	_vm_page_zero_idle
> >  	testl	%eax, %eax
> >  	jnz	idle_loop
> 
> This has some serious bugs:
> (1) ether_poll() is called with interrupts disabled.  This breaks fast
>     interrupt handlers.  ether_poll() uses splimp() so it is apparently
>     not intended to run with priority higher than splhigh().
> (2) The sti/cli stuff belongs in ether_poll(), and the test of the return
>     code of ether_poll() only works because ether_poll() always returns 1.
>     vm_page_zero_idle() and the hlt instruction are never reached and the
>     system spins calling ether_poll() from idle until a process becomes
>     runnable.  ether_poll() needs quite different handling than
>     vm_page_zero_idle() since it can reasonably find something to do
>     whenever an interface is up, while vm_page_zero_idle() soon runs out
>     of things to do if it is called a lot.
> 
> > Index: sys/kern/kern_clock.c
> 
> It shouldn't be necessary to touch this file.  Everything involving
> "ether" certainly doesn't belong here.  Everything related to periodic
> polling can be done, probably more efficiently, using schedsoft*() or
> timeout().  E.g., schedsoftnet() arranges for netisrs to be checked
> for at the next clock interrupt.  But this can now be done almost as
> well (probably better in -current) using an ordinary timeout.
> 
> Bruce
> 
> 
> To Unsubscribe: send mail to majordomo@FreeBSD.org
> with "unsubscribe freebsd-net" in the body of the message

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-net" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20011129063116.B19430>